最近有个需求,需要区分不同渠道所产生的不同结果。
比如,web 端产生的结果,小程序产生的结果,app 产生的结果。实际上表结构是完全相同的,只是做不同的区分。
在体验之后,如果不是大项目,或者分库分表的重要性很高,不推荐用 shareding jdbc。
这玩意问题太多了,文档还少,坑很多。
简单的小项目直接用 mybatis-plus 的动态表名插件即可
分表#
首先想到的当然是分表,大部分分表是基于数据量的分表,因为众所周知的 MySQL 数据库的单表瓶颈。
300W Mysql 可以轻松抗住
600W 数据开始卡,优化可以解决(表结构,索引设计)
800W ~ 1000W 牛逼的 DBA 优化都会遇到瓶颈
而现在的需求是基于业务的分表,所有要自己设置分表的逻辑了。
sharding-jdbc#
要说分库分表就绕不开 SHARDING-JDBC 这个组件。
它定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。它使用客户端直连数据库,以 jar 包形式提供服务,无需二额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
Sharding-JDBC 的核心功能为数据分片和读写分离,通过 Sharding-JDBC,应用可以透明的使用 jdbc 访问已经分库分表、读写分离的多个数据源,而不用关心数据源的数量以及数据如何分布。
安装依赖#
要使用 Sharding-JDBC,首先要做 pom 文件中添加依赖
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>8.0.23</version>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!-- sharding-jdbc 分库分表依赖-->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
需要注意的是,如果使用了 druid,依赖必须使用 druid,而不能是 druid-spring-boot-starter。issues
配置文件#
安装完成后需要在配置文件中声明分库分表的配置及规则
#需要加入下面的配值允许重载bean名称,主要用于后面sql对表的操作,MybatisPlus是根据类名作为表名的
spring.main.allow-bean-definition-overriding=true
#分片策略,多个数据源则用逗号隔开,例如: ds0,ds1
spring.shardingsphere.datasource.names=ds0
#配置数据源内容,下面的ds0 是上面设置的,因此需要同名
spring.shardingsphere.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.url=jdbc:mysql://localhost:3306/jk_test?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=root
#表的位置 在那个数据源(数据库),那个表。 下面的tables.inspection_result中的inspection_result是表名以什么开头
#配置分表指定的哪些表,这里指定了inspection_result和inspection_result_home 2张表
spring.shardingsphere.sharding.tables.inspection_result.actual-data-nodes=ds0.inspection_result, ds0.inspection_result_home
#指定inspection_result表里面主键cid的生成策略 SNOWFLAKE是雪花算法
#spring.shardingsphere.sharding.tables.course.key-generator.column=cid
#spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
#表的分片策略
spring.shardingsphere.sharding.tables.inspection_result.table-strategy.standard.sharding-column=id
#基于业务分表,此处就是自定义的分表策略
spring.shardingsphere.sharding.tables.inspection_result.table-strategy.standard.precise-algorithm-class-name=com.jkkj.config.ResultPreciseShardingAlgorithm
#打开sql输出日志
spring.shardingsphere.props.sql.show=true
自定义分表策略#
可以使用自定义的分表策略来实现业务需求
public class ResultPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> collection, PreciseShardingValue<Long> preciseShardingValue) {
Long id = preciseShardingValue.getValue();
if (id < 8000000) {
return "inspection_result";
} else {
return "inspection_result_home";
}
}
}
根据 id 判断返回的表名即可
范围分片#
我们使用的 strategy.standard.precise
表示的是标准分片策略,它用来提供对 SQL 语句中的 =, IN 的分片操作支持。
思考一下,现在的分片策略是根据 id 大小进行的,如果要查询某个范围内的数据,能不能成功呢?
答案是不能。标准分片不支持范围查询,但可以使用范围分片。
#表的分片策略
spring.shardingsphere.sharding.tables.inspection_result.table-strategy.standard.sharding-column=id
#基于业务分表,此处就是自定义的分表策略
# standard.precise-algorithm 标准策略下分片算法包含2个 precise + range,range是可选的,但是如果使用 range 就必须同 precise 配套一起使用
# 精确分片算法类名称,用于=和IN
spring.shardingsphere.sharding.tables.inspection_result.table-strategy.standard.precise-algorithm-class-name=com.jkkj.config.ResultPreciseShardingAlgorithm
# 范围分片算法类名称,用于BETWEEN,并使其支持<,<=,>,>=
spring.shardingsphere.sharding.tables.inspection_result.table-strategy.standard.range-algorithm-class-name=com.jkkj.config.ResultPreciseShardingAlgorithm
有了范围分片的算法,也要有范围分片的策略
可以看到,范围分片和标准分片使用的是同一个 ResultPreciseShardingAlgorithm
实现类
所有要重新修改下分表策略,新增范围分片
public class ResultPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Integer>, RangeShardingAlgorithm<Integer> {
@Override
public String doSharding(Collection<String> collection, PreciseShardingValue<Integer> preciseShardingValue) {
try {
Integer id = preciseShardingValue.getValue();
if (id < 8000000) {
return "inspection_result";
} else {
return "inspection_result_home";
}
} catch (NumberFormatException e) {
log.error("在分表时id转换异常");
throw new RuntimeException(e);
}
}
@Override
public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Integer> rangeShardingValue) {
Range<Integer> valueRange = rangeShardingValue.getValueRange();
// Integer lowerEndpoint = valueRange.lowerEndpoint();
// Integer upperEndpoint = valueRange.upperEndpoint();
log.info("range : {}", valueRange);
Collection<String> tables = new ArrayList<>();
if (Range.closed(0, 8000000).encloses(valueRange)) {
tables.add("inspection_result");
} else {
tables.add("inspection_result_home");
}
log.info("tables: {}", tables);
return collection;
}
}
完成分表#
其它的业务逻辑不需要修改,在查 inspection_result 表时,Sharding-JDBC 会自动的查询 2 张表并组合。
ShardingSphere
Sharding-jdbc 的实战入门之水平分表(一)
Sharding-JDBC 快速入门(只水平分表)
Sharding-JDBC: 单库分表的实现
Sharding-JDBC 快速入门
shardingsphere 启动的时候报错 Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required
Sharding-JDBC 之 RangeShardingAlgorithm(范围分片算法)
Sharding JDBC (四) 分片策略一:标准分片策略 StandardShardingStrategy