ShardingSphere5.x 版本重构了很多代码以及相关文档不完善,导致个人在集成 ShardingSphere 的过程中问题不断。其中感觉最明显的是集成后 Liquibase 不能正常启动以及容易因为不熟悉 ShardingSphere5.x 导致分库分表配置错误不生效。
MAVEN项目中添加依赖
<!-- 此处引用 v5.1.0,视实际情况修改 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.1.0</version>
</dependency>
配置ShardingSphere5.x
spring:
shardingsphere:
mode:
# 运行模式,!!!在掌握运行模式用途之前建议默认 Memory
type: Memory
props:
# 打印 ShardingSphere 执行信息,
# 若启用未打印信息则调整使用的日志库的日志级别
sql-show: true
datasource:
# 可以用其它名称代替 ds0、ds1
names: ds0, ds1
ds0:
# 支持多种数据源
type: com.zaxxer.hikari.HikariDataSource
# 视 JDBC 版本而定
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/sharding_demo1
username: 数据库用户名
password: 数据库密码
ds1:
# 支持多种数据源
type: com.zaxxer.hikari.HikariDataSource
# 视 JDBC 版本而定
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/sharding_demo2
username: 数据库用户名
password: 数据库密码
rules:
sharding:
tables:
# 把 xxxx_xxxx 替换成实际的表名
xxxx_xxxx:
database-strategy:
standard:
# 分片字段
sharding-column: user_id
# 分片策略名称,具体分片策略定义在 spring.shardingsphere.rules
# .sharding.sharding-algorithms 路径下
sharding-algorithm-name: xxxx-xxxx-inline-strategy
# 默认分表策略,!!!该设置是指自定义了分片的表的默认分表策略,
# 而不是指不分片的表的默认分表策略
default-table-strategy:
none:
# 默认分库策略!!!该设置是指自定义了分片的表的默认分库策略,
# 而不是指不分片的表的默认分库策略
default-database-strategy:
standard:
sharding-column: id
sharding-algorithm-name: id-inline-database-strategy
sharding-algorithms:
# id-inline-database-strategy是自定义的名称,
# !!!最好别以下划线分隔,会有问题
id-inline-database-strategy:
type: INLINE
props:
# 该表达式是指把 id 值是偶数路由到 ds0,奇数路由到 ds1
algorithm-expression: ds$->{id % 2}
# xxxx-xxxx-inline-strategy是自定义的名称,
# !!!最好别以下划线分隔,会有问题
xxxx-xxxx-inline-strategy:
type: INLINE
props:
# 该表达式是指把 user_id 值是偶数路由到 ds0,奇数路由到 ds1
algorithm-expression: ds$->{user_id % 2}
ShardingSphere5.x 不支持默认数据源配置的解决办法
需要添加配置项 spring.shardingsphere.custom.defaultDataSourceName 定义默认数据源。
package magicodex.demo.custom.shardingsphere;
import cn.hutool.core.util.ReflectUtil;
import org.apache.shardingsphere.driver.jdbc.core.datasource.ShardingSphereDataSource;
import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
import org.apache.shardingsphere.infra.metadata.rule.ShardingSphereRuleMetaData;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
import org.apache.shardingsphere.mode.manager.ContextManager;
import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
import org.apache.shardingsphere.singletable.rule.SingleTableRule;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Map;
/**
* <p>
* 设置 ShardingSphereDataSource 对象里的默认数据源属性。
* </p>
*/
@Component
@ConfigurationProperties(prefix = "spring.shardingsphere.custom", ignoreUnknownFields = true)
public class ShardingSphereDataSourcePostProcessor implements BeanPostProcessor {
private String defaultDataSourceName;
public void setDefaultDataSourceName(String defaultDataSourceName) {
this.defaultDataSourceName = defaultDataSourceName;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ShardingSphereDataSource) {
ShardingSphereDataSource dataSource = (ShardingSphereDataSource) bean;
setDefaultDataSourceName(dataSource, defaultDataSourceName);
}
return bean;
}
/**
* 设置默认数据源
*
* @param dataSource
* @param defaultDataSourceName
*/
private void setDefaultDataSourceName(ShardingSphereDataSource dataSource, String defaultDataSourceName) {
ContextManager contextManager = dataSource.getContextManager();
MetaDataContexts metaDataContexts = contextManager.getMetaDataContexts();
Map<String, ShardingSphereMetaData> metaDataMap = metaDataContexts.getMetaDataMap();
Collection<ShardingSphereMetaData> metaDataCollection = metaDataMap.values();
for (ShardingSphereMetaData metaData : metaDataCollection) {
ShardingSphereRuleMetaData ruleMetaData = metaData.getRuleMetaData();
Collection<ShardingSphereRule> rules = ruleMetaData.getRules();
for (ShardingSphereRule rule : rules) {
if (rule instanceof SingleTableRule) {
SingleTableRule singleTableRule = (SingleTableRule) rule;
ReflectUtil.setFieldValue(singleTableRule, "defaultDataSource", defaultDataSourceName);
}
}
}
}
}
参考资料
- 官方分片配置说明 shardingsphere.apache.org/document/5.…
- 官方Spring Boot配置 shardingsphere.apache.org/document/5.…