最近Shardingsphere在Apache Software Foundation 简称ASF 毕业成为Apache顶级项目,也是目前ASF收个分布式数据库中间件项目,未来可期啊,今天我们就搭建一下springboot整合Shardingsphere4.0版本。
依赖:
jdk1.8
maven3.6.3
mybatis plus
mysql8.0
Shardingsphere 4.0
数据库的结构: –| |- ds0 | |- t_order0 | |- t_order1 | |- ds1 |- t_order0 |- t_order1
创建数据库 数据库ds0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 CREATE DATABASE IF NOT EXISTS `ds0` ;USE `ds0` ;SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0 ;DROP TABLE IF EXISTS `t_order0` ;CREATE TABLE `t_order0` ( `order_id` bigint (0 ) NOT NULL COMMENT '订单号(主键)' , `order_name` varchar (255 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '订单名称' , `order_status` int (0 ) NULL DEFAULT NULL COMMENT '订单状态' , `user_id` bigint (0 ) NOT NULL COMMENT '用户id' , PRIMARY KEY (`order_id` ) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;DROP TABLE IF EXISTS `t_order1` ;CREATE TABLE `t_order1` ( `order_id` bigint (0 ) NOT NULL COMMENT '订单号(主键)' , `order_name` varchar (255 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '订单名称' , `order_status` int (0 ) NULL DEFAULT NULL COMMENT '订单状态' , `user_id` bigint (0 ) NOT NULL COMMENT '用户id' , PRIMARY KEY (`order_id` ) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1 ;
数据库ds1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 CREATE DATABASE IF NOT EXISTS `ds1` ;USE `ds1` ;SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0 ;DROP TABLE IF EXISTS `t_order0` ;CREATE TABLE `t_order0` ( `order_id` bigint (0 ) NOT NULL COMMENT '订单号(主键)' , `order_name` varchar (255 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '订单名称' , `order_status` int (0 ) NULL DEFAULT NULL COMMENT '订单状态' , `user_id` bigint (0 ) NOT NULL COMMENT '用户id' , PRIMARY KEY (`order_id` ) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;DROP TABLE IF EXISTS `t_order1` ;CREATE TABLE `t_order1` ( `order_id` bigint (0 ) NOT NULL COMMENT '订单号(主键)' , `order_name` varchar (255 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '订单名称' , `order_status` int (0 ) NULL DEFAULT NULL COMMENT '订单状态' , `user_id` bigint (0 ) NOT NULL COMMENT '用户id' , PRIMARY KEY (`order_id` ) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1 ;
pom.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 <?xml version="1.0" encoding="UTF-8"?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.2.6.RELEASE</version > <relativePath /> </parent > <groupId > com.winterchen</groupId > <artifactId > shardingsphere-demo</artifactId > <version > 0.0.1-SNAPSHOT</version > <name > shardingsphere-demo</name > <description > shardingsphere demo</description > <properties > <java.version > 1.8</java.version > <sharding-sphere.version > 4.0.1</sharding-sphere.version > </properties > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.13</version > <scope > runtime</scope > </dependency > <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-boot-starter</artifactId > <version > 3.1.1</version > </dependency > <dependency > <groupId > org.apache.shardingsphere</groupId > <artifactId > sharding-jdbc-spring-boot-starter</artifactId > <version > ${sharding-sphere.version}</version > </dependency > <dependency > <groupId > org.apache.shardingsphere</groupId > <artifactId > sharding-jdbc-spring-namespace</artifactId > <version > ${sharding-sphere.version}</version > </dependency > </dependencies > <build > <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > </plugin > </plugins > </build > </project >
注意:数据库驱动版本,请根据自己数据库版本进行相关调整,不然会报错
项目配置 application.properties 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 server.port =8098 spring.shardingsphere.datasource.names =ds0,ds1 spring.shardingsphere.datasource.ds0.type =com.zaxxer.hikari.HikariDataSource spring.shardingsphere.datasource.ds0.driver-class-name =com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.ds0.jdbc-url =jdbc:mysql://192.168.133.134:3306/ds0?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&verifyServerCertificate=false&autoReconnct=true&autoReconnectForPools=true&allowMultiQueries=true spring.shardingsphere.datasource.ds0.username =root spring.shardingsphere.datasource.ds0.password =root spring.shardingsphere.datasource.ds1.type =com.zaxxer.hikari.HikariDataSource spring.shardingsphere.datasource.ds1.driver-class-name =com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.ds1.jdbc-url =jdbc:mysql://192.168.133.134:3306/ds1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&verifyServerCertificate=false&autoReconnct=true&autoReconnectForPools=true&allowMultiQueries=true spring.shardingsphere.datasource.ds1.username =root spring.shardingsphere.datasource.ds1.password =root spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column =user_id spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression =ds$->{user_id % 2} spring.shardingsphere.sharding.tables.t_order.actual-data-nodes =ds$->{0..1}.t_order$->{0..1} spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column =order_id spring.shardingsphere.sharding.tables.t_order.key-generator.column =order_id spring.shardingsphere.sharding.tables.t_order.key-generator.type =SNOWFLAKE spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression =t_order$->{order_id % 2} spring.shardingsphere.props.sql.show =true spring.main.allow-bean-definition-overriding =true mybatis-plus.mapper-locations =classpath:/mapper/*.xml mybatis-plus.configuration.jdbc-type-for-null ='null'
注意:数据库连接配置、mybatis-plus扫包路径,需要根据实际情况进行改变
以上的配置实现了分库分表,一下几点概念需要明白:
逻辑表 水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例:订单数据根据主键尾数拆分为10张表,分别是t_order0到t_order9,他们的逻辑表名为t_order。
真实表 在分片的数据库中真实存在的物理表。即上个示例中的t_order0到t_order9。
数据节点 数据分片的最小单元。由数据源名称和数据表组成,例:ds0.t_order0。
分片键 用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。 SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,ShardingSphere也支持根据多个字段进行分片。
分片算法 通过分片算法将数据分片,支持通过=、>=、<=、>、<、BETWEEN和IN分片。分片算法需要应用方开发者自行实现,可实现的灵活度非常高。
目前提供4种分片算法。由于分片算法和业务实现紧密相关,因此并未提供内置分片算法,而是通过分片策略将各种场景提炼出来,提供更高层级的抽象,并提供接口让应用开发者自行实现分片算法。
对应PreciseShardingAlgorithm,用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用。
对应RangeShardingAlgorithm,用于处理使用单一键作为分片键的BETWEEN AND、>、<、>=、<=进行分片的场景。需要配合StandardShardingStrategy使用。
对应ComplexKeysShardingAlgorithm,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用。
对应HintShardingAlgorithm,用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用。
分片策略 包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。目前提供5种分片策略。
对应StandardShardingStrategy。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。RangeShardingAlgorithm是可选的,用于处理BETWEEN AND, >, <, >=, <=分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。
对应ComplexShardingStrategy。复合分片策略。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。
对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: t_user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0到t_user_7。
对应HintShardingStrategy。通过Hint指定分片值而非从SQL中提取分片值的方式进行分片的策略。
对应NoneShardingStrategy。不分片的策略。
SQL Hint 对于分片字段非SQL决定,而由其他外置条件决定的场景,可使用SQL Hint灵活的注入分片字段。例:内部系统,按照员工登录主键分库,而数据库中并无此字段。SQL Hint支持通过Java API和SQL注释(待实现)两种方式使用。
自增主键生成策略 通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。 采用UUID.randomUUID()的方式产生分布式主键。或者 SNOWFLAKE
mybatis-plus mybatis-plus极大的提高了开发效率,简单的配置和使用mybatis-plus
配置mybatis-plus的分页
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.winterchen.shardingspheredemo.configuration;@EnableTransactionManagement @Configuration @MapperScan ("com.winterchen.shardingspheredemo.dao" )public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor () { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize()); return paginationInterceptor; } }
配置自定义的通用mapper
1 2 3 4 5 6 7 8 9 10 11 package com.winterchen.shardingspheredemo.configuration;import java.util.Map;public interface MyBaseMapper <T > extends BaseMapper <T > { IPage<T> selectAllByCondition (Page<?> page, @Param("condition" ) Map<String, Object> condition) ; int deleteById (@Param("condition" ) Map<String, Object> condition) ; }
代码 实体类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.winterchen.shardingspheredemo.model;@TableName ("t_order" )public class OrderInfo { @TableId (value = "order_id" ) private Long orderId; @TableField (value = "order_name" ) private String orderName; @TableField (value = "order_status" ) private Integer orderStatus; @TableField (value = "user_id" ) private Long userId; }
Mapper mapper 1 2 3 4 5 6 7 8 9 10 package com.winterchen.shardingspheredemo.dao;public interface OrderMapper extends MyBaseMapper <OrderInfo > { IPage<OrderInfo> selectAllByCondition (Page<?> page, @Param("condition" ) Map<String, Object> condition) ; int deleteById (@Param("condition" ) Map<String, Object> condition) ; }
mapper xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.winterchen.shardingspheredemo.dao.OrderMapper" > <sql id ="Base_Column_List" > order_id, order_name, order_status, user_id </sql > <select id ="selectAllByCondition" resultType ="com.winterchen.shardingspheredemo.model.OrderInfo" > select <include refid ="Base_Column_List" /> from t_order <where > <if test ="condition.userId != null" > and user_id = #{condition.userId, jdbcType=BIGINT} </if > <if test ="condition.orderId != null" > and order_id = #{condition.orderId, jdbcType=BIGINT} </if > <if test ="condition.orderName != null and condition.orderName != ''" > and order_name like concat('%',#{condition.orderName,jdbcType=VARCHAR} ,'%') </if > <if test ="condition.orderStatus != null" > and order_status = #{condition.orderStatus, jdbcType=INTEGER} </if > </where > </select > <delete id ="deleteById" > delete from t_order where order_id = #{condition.orderId, jdbcType=BIGINT} and user_id = #{condition.userId, jdbcType=BIGINT} </delete > </mapper >
service 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.winterchen.shardingspheredemo.service;public interface OrderService extends IService <OrderInfo > { @Override boolean save (OrderInfo entity) ; @Override boolean removeById (Serializable id) ; @Override boolean updateById (OrderInfo entity) ; IPage<OrderInfo> pageOrderInfos (Page<?> page, OrderInfo orderInfo) ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.winterchen.shardingspheredemo.service.impl;@Service public class OrderServiceImpl extends ServiceImpl <OrderMapper , OrderInfo > implements OrderService { @Override public boolean save (OrderInfo entity) { return super .save(entity); } @Override public boolean removeById (Serializable id) { return super .removeById(id); } @Override public boolean updateById (OrderInfo entity) { return super .updateById(entity); } @Override public IPage<OrderInfo> pageOrderInfos (Page<?> page, OrderInfo orderInfo) { Map<String, Object> map = new HashMap<>(); map.put("userId" , orderInfo.getUserId()); map.put("orderId" , orderInfo.getOrderId()); map.put("orderName" , orderInfo.getOrderName()); map.put("orderStatus" , orderInfo.getOrderStatus()); return super .baseMapper.selectAllByCondition(page, map); } }
controller 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package com.winterchen.shardingspheredemo.controller;@RestController @RequestMapping ("/api/v1/order" )public class OrderController { @Autowired private OrderService orderService; @PostMapping ("" ) public boolean save (@RequestBody OrderInfo orderInfo) { return orderService.save(orderInfo); } @DeleteMapping ("/{orderId}" ) public boolean deleteById ( @PathVariable("orderId" ) Long id) { return orderService.removeById(id); } @PutMapping ("/{orderId}" ) public boolean updateById ( @PathVariable("orderId" ) Long orderId, @RequestBody OrderInfo orderInfo) { orderInfo.setOrderId(orderId); return orderService.updateById(orderInfo); } @GetMapping ("/list" ) public IPage page ( @RequestParam(name = "pageNum" , required = false , defaultValue = "1" ) Integer pageNum, @RequestParam (name = "pageSize" , required = false , defaultValue = "10" ) Integer pageSize, @RequestParam (name = "orderId" , required = false ) Long orderId, @RequestParam (name = "orderStatus" , required = false ) Integer orderStatus, @RequestParam (name = "orderName" , required = false ) String orderName) { Page<OrderInfo> page = new Page<>(pageNum,pageSize); OrderInfo orderInfo = new OrderInfo(); orderInfo.setOrderId(orderId); orderInfo.setOrderName(orderName); orderInfo.setOrderStatus(orderStatus); return orderService.pageOrderInfos(page, orderInfo); } }
启动类 1 2 3 4 5 6 7 8 9 10 11 12 package com.winterchen.shardingspheredemo;@SpringBootApplication public class ShardingsphereDemoApplication { public static void main (String[] args) { SpringApplication.run(ShardingsphereDemoApplication.class , args ) ; } }
以上就整合完毕了,可以使用postMan进行测试,测试截图就不展示了,后面会介绍关于读写分离的相关介绍,如果需要查看详细的介绍可以参考官方文档。
相关资源