Spring整合sharding-jdbc使用踩坑
前言
项目中需要对数据库进行分库分表操作,所以使用sharding-jdbc来实现此功能
引入依赖
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
简单原理分析
- org.apache.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration 导入自动配置类,根据配置文件中配置的信息创建 DateSource 列表
- 创建 ShardingDataSource 替代之前的 DateSource 列表
- 获取连接的实现类为 ShardingConnection
踩坑1
背景
项目中需要配置两套数据源,一套走分表,一套不走。
错误
会报错找不到事务执行器TransactionTemplate的Bean,本质上还是找不到TransactionManager
解决方式
通过手动配置这两个Bean解决了,根本原因为项目代码中自定义了一个DataSource,sharding-jdbc自动配置中也定义了一个通用DataSource但是没有设置为Primary,导致JdbcTransactionManagerConfiguration不能自动加载。
通过自定义BeanDefinitionRegistryPostProcessor也不能解决,因为它会在ConfigurationClassPostProcessor之后执行,如果想让它在ConfigurationClassPostProcessor之前执行,它又找不到DataSource这个BeanDefinition,所以这种方法行不通,只能手动配置TransactionManager了。
踩坑2
查询条件如果不包含分片列或者操作符不是(=,in,between),不会走分片算法
踩坑3
分库分表之后,更新或删除或查询操作的条件也必须带上分片键,不然会扫描所有库和表。
具体可以看org.apache.shardingsphere.core.route.type.standard.StandardRoutingEngine#getDataNodes方法
通过 spring.shardingsphere.props.sql.show=true 可以看到最终执行的SQL
踩坑4
背景
spring.shardingsphere.datasource.names=ds0_master,ds0_slave0
# 配置第1库的主从
spring.shardingsphere.datasource.ds0_master.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds0_master.driver-class-name=com.mysql.jdbc.Driver
在配置分库分表时遇到报错
Reason: Canonical names should be kebab-case ('-' separated), lowercase alpha-numeric characters and must start with a letter
原因
前缀不能包含下划线,spring.shardingsphere.datasource.${databaseName}
模拟报错
public static void main(String[] args) {
Map<String, Object> map = new HashMap<>();
map.put("bo_go.private_key.apikey", "abc");
MapPropertySource propertySource = new MapPropertySource("test", map);
StandardEnvironment environment = new StandardEnvironment();
environment.getPropertySources().addFirst(propertySource);
Binder binder = Binder.get(environment);
BindResult<BogoConfig> bindResult = binder.bind("bo_go", BogoConfig.class);
System.out.println(bindResult);
}
解决方式
使用中划线 ds0-master
spring.shardingsphere.datasource.names=ds0-master,ds0-slave0
# 配置第1库的主从
spring.shardingsphere.datasource.ds0-master.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds0-master.driver-class-name=com.mysql.jdbc.Driver
踩坑5
第一次请求数据库很慢,要2-3秒(第二次仅需200ms),通过arthas分析,发现主要耗时在 创建 SQL解析器
profiler start -- 开启采样
profiler stop --format flamegraph -- 结束采样并生成火焰图
优化方案如下,优化前 2.4S,优化后1.2S,会提前加载 OptimizeEngineFactory 和 RoutingEngineFactory
@Slf4j
@Configuration
@ConditionalOnProperty(value = "shardingsphere.preload.enabled", havingValue = "true", matchIfMissing = true)
public class ShardingPreLoadConfig implements InitializingBean {
@Autowired
private MarketingBatchOrderMapper batchOrderMapper;
@Override
public void afterPropertiesSet() throws Exception {
String batchOrderId = "xxx";
// 触发 SQL 解析引擎预热
batchOrderMapper.selectByPrimaryKey(batchOrderId);
log.info("sharding-jdbc SQL解析引擎预热");
}
}
分片算法优化
分库分表分片算法优化: 分库分表联合取模
原理:将分库和分表视为一个整体分片(总片数=4×16=64),再分解为库和表索引。
优势:确保所有库表组合均被覆盖,避免空洞
int totalShards = 64; // 4库 × 16表
int shardIndex = Math.abs(hash) % totalShards;
int dbIndex = shardIndex / 16; // 分库索引
int tableIndex = shardIndex % 16; // 分表索引

浙公网安备 33010602011771号