这篇是ShardingSphere-JDBC+Springboot+MybatisPlus+Druid分库分表的简单例子,我们用一个订单表为例,通过简单配置实现数据分片到多个数据库的多个表中。
主要配置和代码已经在文中给出,完整例子可以参考 GitHub - fruitbasket-litchi-shardingjdbc。
在一个或两个MySQL服务上创建两个数据库(order_database),执行下面的脚本创建三个订单表(t_order、t_order_0、t_order_1)。
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
`order_id` bigint NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`description` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
DROP TABLE IF EXISTS `t_order_0`;
CREATE TABLE `t_order_0` (
`order_id` bigint NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`description` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=671005327373635585 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
DROP TABLE IF EXISTS `t_order_1`;
CREATE TABLE `t_order_1` (
`order_id` bigint NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`description` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=671005326614466562 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
<properties>
<java.version>1.8java.version>
<maven.compiler.source>${java.version}maven.compiler.source>
<maven.compiler.target>${java.version}maven.compiler.target>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<spring-boot-dependencies.version>2.3.12.RELEASEspring-boot-dependencies.version>
<shardingsphere.version>5.0.0shardingsphere.version>
<mybatis-plus-boot-starter.version>3.4.3.4mybatis-plus-boot-starter.version>
<lombok.version>1.18.22lombok.version>
<mybatis-spring-boot-starter>2.2.0mybatis-spring-boot-starter>
<druid.version>1.2.8druid.version>
<mybatis-plus-generator.version>3.4.1mybatis-plus-generator.version>
<freemarker.version>2.3.31freemarker.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot-dependencies.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.apache.shardingspheregroupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starterartifactId>
<version>${shardingsphere.version}version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>${mybatis-plus-boot-starter.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
<scope>providedscope>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>${druid.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>${mybatis-plus-generator.version}version>
dependency>
<dependency>
<groupId>org.freemarkergroupId>
<artifactId>freemarkerartifactId>
<version>${freemarker.version}version>
dependency>
dependencies>
配置数据源,指定两个库(db0、db1)的数据源(druid)、地址和用户名密码等信息。
配置数据库和表的分片算法(sharding-algorithms),并指定分片算法表达式(algorithm-expression),给算法自定义别名(database-inline、t-order-inline)。表达式中(如:db$->{user_id % 2}
)的意思是数据库名字为db加上$->{user_id % 2}
的结果,也就是user_id%2
的结果(0或1),拼起来意思是根据user_id分散到数据库db0或db1中。表达式中$->{}
也可以写成${}
,为了避免和SpringBoot配置冲突建议不写${}
形式。
这里另外配置了主键生成器(key-generators),并为这个配置自定义别名(snowflake),生成类型为雪花算法(SNOWFLAKE)。
下面tables中的是对一个或多个表进行单独配置。
配置数据库策略(databaseStrategy),指定分片字段(shardingColumn)为user_id、分片算法名称(shardingAlgorithmName)为database-inline(上面自定义的别名)。
再往下配置表策略(tableStrategy)和主键生成策略(keyGenerateStrategy)也是一个意思,用上面定义的配置。
spring:
shardingsphere:
# 数据源
datasource:
names: db0,db1
db0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql_node0:3306/order_database?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
db1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql_node1:3306/order_database?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
rules:
sharding:
# 分片算法
sharding-algorithms:
# 数据库
database-inline:
type: INLINE
props:
algorithm-expression: db$->{user_id % 2}
# t-order表
t-order-inline:
type: INLINE
props:
algorithm-expression: t_order_$->{order_id % 2}
# 主键生成策略
key-generators:
snowflake:
type: SNOWFLAKE
props:
worker-id: 001
tables:
t_order:
actualDataNodes: db$->{0..1}.t_order_$->{0..1}
# 数据策略
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: database-inline
# 表策略
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: t-order-inline
# 主键策略
keyGenerateStrategy:
column: order_id
keyGeneratorName: snowflake
props:
sql-show: true
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
配置结果是添加的数据根据user_id%2确定分片的数据库(db0、db1)/(mysql_node0、mysql_node1),再根据order_id%2保存到分片的表中。也就意味着共有4个表来存储订单数据。
这里提供了添加数据(add,http://localhost:8080/order/add)和列出数据(list,http://localhost:8080/order/list)两个接口。
package cn.fruitbasket.litchi.shrdingjdbc.controller;
import cn.fruitbasket.litchi.shrdingjdbc.entity.TOrder;
import cn.fruitbasket.litchi.shrdingjdbc.service.ITOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ThreadLocalRandom;
import static java.util.stream.Collectors.toList;
@RestController
@RequestMapping("order")
public class TOrderController {
@Autowired
private ITOrderService itOrderService;
@GetMapping("add")
public String add() {
TOrder order = new TOrder()
.setUserId(ThreadLocalRandom.current().nextInt(0, Integer.MAX_VALUE))
.setDescription("测试订单");
itOrderService.save(order);
return order.toString();
}
@GetMapping("list")
public String list() {
return itOrderService.list().stream()
.map(tOrder -> tOrder.toString() + "
").collect(toList()).toString();
}
}
通过浏览器GET方式访问接口,查看数据库可以看到数据分散到了不同表中。
ShardingSphere - 使用 SPRING BOOT STARTER
GitHub - fruitbasket-litchi-shardingjdbc