前言
由于分库分表跟业务贴切相关,所以云数据库是不支持分库分表的配置的,我们想要实现分库分表,读写分离等功能,大都使用使用mycat中间件,或者ShardingJDBC代码嵌入式插件。
正文
那么如何使用ShardingJDBC呢,简单介绍下本人事件的过程和细节。一开始的时候项目架构并没有直接使用ShardingJDBC,而是用了DynamicDataSource做了动态数据源的配置(为了实现读写分离),后来我的思路就一直限制在如何整合DynamicDataSource和ShardingJDBC,结果就是一直整合不成功。经过一个晚上的冥思苦想(其实睡得贼香),第二天决定换个思路,本来ShardingJDBC就支持读写分离,还要DynamicDataSource做什么,直接干掉,搞上ShardingJDBC依赖,配置,然后调试成功。
依赖:
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
yaml配置(分表+读写分离):
参考:ShardingJDBC实战(一):按年月分表_ztr007的博客-CSDN博客_shardingjdbc按时间分表
spring:
sharding-sphere:
# 是否开启SQL显示
props:
sql:
show: false
datasource:
names: master,slave
master:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:mysql://***.124.3.52:3306/test?useUnicode=true&characterEncoding=UTF-8&useOldAliasMetadataBehavior=true&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=true&allowPublicKeyRetrieval=true
username: ***
password: ***
slave:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:mysql://***.124.3.52:3306/test?useUnicode=true&characterEncoding=UTF-8&useOldAliasMetadataBehavior=true&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=true&allowPublicKeyRetrieval=true
username: ***
password: ***
sharding:
# ====================== ↓↓↓↓↓↓ 读写分离配置 ↓↓↓↓↓↓ ======================
master-slave-rules:
master:
# 主库
masterDataSourceName: master
# 从库
slaveDataSourceNames:
- slave
# 从库查询数据的负载均衡算法 目前有2种算法 round_robin(轮询)和 random(随机)
# 算法接口 org.apache.shardingsphere.spi.masterslave.MasterSlaveLoadBalanceAlgorithm
# 实现类 RandomMasterSlaveLoadBalanceAlgorithm 和 RoundRobinMasterSlaveLoadBalanceAlgorithm
loadBalanceAlgorithmType: ROUND_ROBIN
# ====================== ↓↓↓↓↓↓ 按月份分表配置 ↓↓↓↓↓↓ ======================
tables:
t_login_record:
actual-data-nodes: master.t_login_record
# 添加数据分表策略
table-strategy:
standard:
sharding-column: create_time
precise-algorithm-class-name: com.social.live.common.conf.shardingJDBC.StatisticShardingAlgorithm
range-algorithm-class-name: com.social.live.common.conf.shardingJDBC.StatisticShardingAlgorithm
import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import org.springframework.util.CollectionUtils;
import java.sql.Date;
import java.util.Collection;
/*基于日期的标准分片算法*/
public class StatisticShardingAlgorithm
implements PreciseShardingAlgorithm<Date>, RangeShardingAlgorithm<Date> {
/**
* 精确分片算法类名称,用于=和IN
*
* @param collection
* @param preciseShardingValue
* @return
*/
@Override
public String doSharding(Collection<String> collection,
PreciseShardingValue<Date> preciseShardingValue) {
if (!CollectionUtils.isEmpty(collection)) {
String logicTable = collection.stream().findFirst().get();
return TableNameData.getTableByDate(logicTable, preciseShardingValue.getValue());
} else {
throw new IllegalArgumentException(
"sharding jdbc not find logic table,please check config");
}
}
/**
* 范围分片算法类名称,用于BETWEEN,可选
*
* @param collection
* @param rangeShardingValue
* @return
*/
@Override public Collection<String> doSharding(Collection<String> collection,
RangeShardingValue<Date> rangeShardingValue) {
if (!CollectionUtils.isEmpty(collection)) {
String logicTable = collection.stream().findFirst().get();
Range<Date> range = rangeShardingValue.getValueRange();
Date start = range.lowerEndpoint();
Date end = range.upperEndpoint();
return TableNameData.getTableSet(logicTable, start, end);
} else {
throw new IllegalArgumentException(
"sharding jdbc not find logic table,please check config");
}
}
}
最后附上官网连接:Yaml Configuration :: ShardingSphere
参数解析:
spring:
shardingsphere:
dataSources: #数据源配置,可以配置多个
<data_source_name>: #<数据源池实现类> 具体的数据源
driverClassName: #数据库驱动名
url: #数据库连接
username: #数据库名
password: #数据库密码
shardingRule:
tables: #需要进行分表的逻辑表
<logic_table_name>: #逻辑表名
actualDataNodes: #描述数据源名称和实际表,分隔符为点,多个数据节点用逗号分隔,支持内联表达式。这意味着只对数据库进行分片。示例:ds${0..7}.tbl${1..0}
tableStrategy: #表分片策略,如果没有,则使用默认的数据库分片战略。下面的分片策略只能选择一种。
standard: #单分片列的标准分片场景
shardingColum: #用于分片的列名称
preciseAlgorithmClassName: #用于“=”和“IN”的精确算法类名。此类需要实现PreciseShardingAlgorithm,并且需要无参数构造函数
rangeAlgorithmClassName: #用于“between”之间的范围算法类名。此类需要实现RangeShardingAlgorithm,并且需要无参数构造函数
complex: #多个分片列的复杂分片场景
shardingColumns: #分片列的名称。用逗号分隔的多列
algorithmClassName: #复杂分片算法类名。此类需要实现ComplexKeysShardingAlgorithm,并且需要无参数构造函数
inline: #单分片列的内联表达式分片场景
shardingColum: #用于分片的列名称
algorithmInlineExpression: #切分算法的内联表达式
hint: #提示切分策略
algorithmClassName: #提示切分算法类名。这个类需要实现HintShardingAlgorithm,并且需要一个无参数构造函数
none: #不分片
databaseStrategy: #数据库分片策略,与表分片策略一样
keyGenerator:
column: #键生成器的列名
type: #键生成器的类型 SNOWFLAKE或UUID
props: #关于属性,请注意:当使用雪花时,`worker'。id'和'max.time.difference。需要设置“雪花”的毫秒数。要使用此算法的生成值作为分片值,建议配置“max.vibration.offset”`
bindingTables: #绑定表规则配置
props:
sql.show: #是否打印sql,默认为false
executor.size: #工作线程数,默认CPU线程数
check:
table:
metadata:
enabled: #若要检查所有表的元数据一致性,默认值:false
max:
connections:
size:
per:
query: #每个物理数据库的每个查询分配的最大连接数。默认值:1
说明点:
分库分表了以后,对于增删改查操作,会尽可能缩小范围,如果sql语句中的条件涉及了分片键,那么sharding jdbc会将这条sql路由到可能出现的表中执行,如果sql语句中没有涉及分片键,那么sharding jdbc会将sql路由到所有的表中执行。因此如果项目中使用到了分库分表,那么在后期编写sql的时候尽可能使用上带分片键的sql语句,避免没有必要的sql开销。