写在文章开头
有读者公司项目引入多数据源情况下,引入sharding-jdbc
会出现各种奇奇怪怪的报错,对此笔者结合报错原因查阅网上资料和底层源码运行机制找到了相对简单的适配步骤,遂以此文分享一下整个过程,希望对你有帮助。

Hi,我是 sharkChili ,是个不断在硬核技术上作死的技术人,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili 。
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。
详解mybatis多数据源如何适配sharding-jdbc
详解问题根源
本质上出现问题原因就是mybatis-plus
多数据源和shardingsphere
都存在数据源配置,而两者的starter
都会进行数据源自动装配进而导致配置冲突。
以笔者配置的实验为例,对应AccountMapper
需要使用dynamic
多数据源下的某个数据源,而当前我们却注入了两套数据源,最终导致AccountMapper
这个bean
注入失败,导致程序无法正常启动。

这里笔者也贴出排查过程中,Spring
容器的情况,可以看到在抛出异常时,容器中存在两套数据源,导致AccountMapper
在进行bean
创建时无法得到正确的sqlsessionTemplate
,进而导致Error creating bean with name 'accountMapper' defined in file
的错误:

对应的解决方案也比较简单,就是在两套数据源进行自动装配时,将shardingsphere
的数据源整合到dynamic
多数据源中,让dynamic
多数据源同理管理所有的数据库连接信息:

了解了错误和解决思路之后,我们先给出对应的dynamic数据源
和shardingsphere
数据源配置,后续步骤我们将会把这两套数据源整合成一套:
# dynamic多数据源配置 db0和db1
spring.datasource.dynamic.primary=db0
spring.datasource.dynamic.datasource.db0.url=jdbc:mysql://127.0.0.1:3306/db0?characterEncoding=UTF8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&allowMultiQueries=true
spring.datasource.dynamic.datasource.db0.username=root
spring.datasource.dynamic.datasource.db0.password=123456
spring.datasource.dynamic.datasource.db0.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.dynamic.datasource.db1.url=jdbc:mysql://127.0.0.1:3306/db1?characterEncoding=UTF8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&allowMultiQueries=true
spring.datasource.dynamic.datasource.db1.username=root
spring.datasource.dynamic.datasource.db1.password=123456
spring.datasource.dynamic.datasource.db1.driverClassName=com.mysql.cj.jdbc.Driver
# shardingsphere 数据源配置
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/sd1?characterEncoding=utf-8
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456
解决思路
如下所示,笔者通过AutoConfigureBefore
在两个数据源进行自动装配前进行数据源整合,首先通过dynamicDataSourceProvider
将shardingsphere
的数据源封装成DynamicDataSourceProvider
并实现其loadDataSources
方法,将分库分表的数据源存到dataSourceMap
中,通过dataSource方法将配置文件配置为primary
的数据源作为master
数据源,实现数据源加载的有序性:
@Configuration
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class,
SpringBootConfiguration.class})
public class DataSourceConfiguration {
@Autowired
private DynamicDataSourceProperties properties;
@Lazy
@Resource
AbstractDataSourceAdapter shardingDataSource;
@Bean
public DynamicDataSourceProvider dynamicDataSourceProvider() {
Map<String, DataSourceProperty> datasourceMap = properties.getDatasource();
return new AbstractDataSourceProvider() {
@Override
public Map<String, DataSource> loadDataSources() {
Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap);
// 将 shardingjdbc整合到dynamic多数据源中
dataSourceMap.put("sharding", shardingDataSource);
return dataSourceMap;
}
};
}
/**
* 将动态数据源设置为primary配置项目的
*/
@Primary
@Bean
public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.setPrimary(properties.getPrimary());
dataSource.setStrict(properties.getStrict());
dataSource.setStrategy(properties.getStrategy());
dataSource.setP6spy(properties.getP6spy());
dataSource.setSeata(properties.getSeata());
return dataSource;
}
}
完成上述配置后,我们可以在程序启动成功后看到所有数据源都归整为1个,并且dynamic
和shardingsphere
的数据源也都存在于数据源中:

配置结果验收
我们通过代码进行测试:
private static void sd1Test() {
ProductOrder productOrder = new ProductOrder();
productOrder.setId(1L);
productOrder.setName("product");
ProductOrderMapper productOrderMapper = SpringUtil.getBean(ProductOrderMapper.class);
productOrderMapper.insert(productOrder);
}
从插入情况来看,对应的产品表就走到了对应的分表上:
2024-09-13 18:07:26.672 INFO 29096 --- [ main] ShardingSphere-SQL : Actual SQL: ds0 ::: insert into product_order_1 (id, `name`)
values (?, ?) ::: [1, product]
小结
自此我们将shardingsphere
和dynamic
数据源完成了整合,实现多数据源场景下使用分库分表的操作,本文到此结束,希望这套方案对你有帮助。
我是 sharkchili ,CSDN Java 领域博客专家,mini-redis的作者,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili 。 因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。
参考
项目集成shanrding-jdbc报错:https://www.cnblogs.com/zhangxl1016/p/16709484.html
集成sharding jdbc和多数据源:https://juejin.cn/post/7127569081082839048
踩坑 sharding jdbc,集成多数据源 - 转载自知乎:https://my.oschina.net/sprouting/blog/5379388




