写在文章开头
Sharding-JDBC
是一款比较轻量级的分库分表框架,它使用客户端直连数据库,通过jar包形式提供服务,通过对数据源进行增强实现分库分表逻辑实现,同时它也很市面上的各种ORM框架完全兼容,所以就会以一个简单的用户查询的给出Sharding-JDBC
基础入门教程。
Hi,我是 sharkChili ,是个不断在硬核技术上作死的 java coder ,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili 。
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。
Sharding-JDBC基础案例演示
前置步骤
Sharding-JDBC
底层通过封装MySQL
默认的方式实现分表逻辑,所以对于市面上主流的ORM
框架都是支持的,在使用之前引入Sharding-JDBC
的依赖:
<!-- Sharding-JDBC -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
然后我们再给出本次的分表的DDL
语句,我们以user_0
为例对应的语句如下所示,另外的user_1
、user_2
结构是一致的这里就不多赘述了:
CREATE TABLE `user_0` (
`id` bigint NOT NULL,
`name` varchar(20) NOT NULL,
`food_id` bigint NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
配置数据源
Sharding-JDBC
通过对原始的数据源进行封装从而拓展出分库分表的逻辑,所以使用时也需要配置Sharding-JDBC
的数据源信息,可以看到除了必要的账号密码以外,还有就是分库分表算法了,以笔者本次的示例来说,仅需要分表算法,所以仅仅通过通过table-strategy
配置完成对id
的分表取模算法:
#数据源名称(随便起名,如果有多个库,逗号隔开 ds0,ds1,ds2)
spring.shardingsphere.datasource.names=ds0
# 数据源
spring.shardingsphere.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.url=jdbc:mysql://localhost:3306/db?characterEncoding=utf-8
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=xxxx
#分表策略配置
##表名枚举,其中的user是需要分表的表名;ds0.user_$->{0..2} 其中ds0表示数据源名称;user_$->{0..2} 表示从user_0到user_2
spring.shardingsphere.sharding.tables.user.actual-data-nodes=ds0.user_$->{0..2}
##使用哪一列用作计算分表策略,我们就使用id
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=id
##具体的分表路由策略,我们有3个user表,使用主键id取余3,余数0/1/2分表对应表user_0,user_2,user_2
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id % 3}
##配置主键生成策略,因为多张表了,id不能在配置数据库自增,需要配置主键生成策略,user表主键名称是id
spring.shardingsphere.sharding.tables.user.key-generator.column=id
##id使用雪花算法,因为雪花算法生成的id具有全球唯一性,并且又有自增特性,适合mysql的innodb引擎
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE
# 打开sql输出日志
spring.shardingsphere.props.sql.show=true
分表的CRUD操作
基于上述配置Spring boot
就会完成Sharding-JDBC数据源的装配从而完成分表工具的加载,这里我们先给出一段插入示例,我们设置id为1,按照分表算法,这条数据最终会落user_1上:
@Test
void insert() {
User user = new User();
user.setId(1L);
user.setName("user" + 1);
user.setFoodId(0L);
userMapper.insert(user);
}
最终我们从打印日志印证了这一点,这条数据确实插入到user_1 表:
2024-04-24 23:53:43.266 INFO 25532 --- [ main] ShardingSphere-SQL : Actual SQL: ds0 ::: insert into user_1 (id, name, food_id) VALUES (?, ?, ?) ::: [1, user1, 0]
同理我们进行查询id为1的操作:
@Test
void selectByExample() {
UserExample userExample = new UserExample();
userExample.createCriteria().andIdEqualTo(1L);
log.info("query user:{}", userMapper.selectByExample(userExample).stream().findFirst().orElse(null));
}
从输出的日志来看,还是定位到了user_1表,并成功查询到了数据:
2024-04-24 23:56:27.050 INFO 15480 --- [ main] ShardingSphere-SQL : Actual SQL: ds0 ::: select
id, `name`, food_id
from user_1
WHERE ( id = ? ) ::: [1]
2024-04-24 23:56:27.068 INFO 15480 --- [ main] com.sharkChili.mapper.UserMapperTest : query user:com.sharkChili.domain.User@25218a4d
详解Sharding-JDBC工作原理
Sharding-JDBC
的脚手架本质上就是基于Spring boot
的自动装配原理,将我们配置的分库分表数据源、算法等信息生成ShardingDataSource
,当我们基于Mybatis
等框架进行CRUD
操作时,ShardingDataSource
就会返回它所实现的ShardingConnection
,通过ShardingConnection
的PreparedStatement
的execute
方法获取当前的SQL
,并基于我们配置的算法生成新的SQL
语句并提交到数据库执行从而得到结果:
回到源码,在Sharding-JDBC
的脚手架中我们定位到spring.factories
所要加载的SpringBootConfiguration
,可以看到它基于配置生成ShardingDataSource
的逻辑:
@Bean
public DataSource dataSource() throws SQLException {
//......
//基于配置中加载的信息所得到的dataSourceMap、分表策略配置信息shardingProperties生成ShardingDataSource
return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingSwapper.swap(shardingProperties), propMapProperties.getProps());
}
以查询操作为例,代码会从Mybatis
的代理的执行器SimpleExecutor
走到doQuery
方法,它会通过prepareStatement
方法拿到ShardingConnection
对应的prepareStatement
,然后通过query
进行查询:
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//通过`prepareStatement`方法拿到`ShardingConnection`对应的`prepareStatement`
stmt = prepareStatement(handler, ms.getStatementLog());
//执行分库分表查询
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
shard
方法内部会走到StandardRoutingEngine
的routeTables
方法,该方法通过我们配置的tables.user.table-strategy.inline.algorithm-expression=user_$->{id % 3}
得到一个InlineShardingStrategy
,而InlineShardingStrategy
策略内部会使用我们的id % 3
生成Closure
对象,而的doCall
方法的逻辑就是id % 3
,这也就意味着我们传入的id
实际上就是通过InlineShardingStrategy
内部生成的Closure
得到分表结果:
对应我们的也给出对应的核心代码示例,自此我们就将Sharding-JDBC
的核心逻辑剖析完毕了:
private Collection<DataNode> routeTables(final TableRule tableRule, final String routedDataSource, final List<RouteValue> tableShardingValues) {
Collection<String> availableTargetTables = tableRule.getActualTableNames(routedDataSource);
//通过shardingRule.getTableShardingStrategy获取分表策略并调用doSharding得到结果表
Collection<String> routedTables = new LinkedHashSet<>(tableShardingValues.isEmpty() ? availableTargetTables
: shardingRule.getTableShardingStrategy(tableRule).doSharding(availableTargetTables, tableShardingValues));
Preconditions.checkState(!routedTables.isEmpty(), "no table route info");
Collection<DataNode> result = new LinkedList<>();
for (String each : routedTables) {
result.add(new DataNode(routedDataSource, each));
}
return result;
}
小结
以上便是笔者对于Sharding-JDBC
分库分表算法配置与实现的剖析,后续我们还会对与分页查询、自定义分库分表算法的实现进行着重介绍,希望对你有帮助,感谢您的阅读。
我是 sharkchili ,CSDN Java 领域博客专家,开源项目—JavaGuide contributor,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili 。 因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。
参考
SPRING BOOT配置:https://shardingsphere.apache.org/document/4.1.1/cn/manual/sharding-jdbc/configuration/config-spring-boot/
分库分表神器sharding-jdbc在springboot中的全场景使用demo:https://blog.csdn.net/csdn_20150804/article/details/118252213
本文使用 markdown.com.cn 排版