一、分片列(Sharding Column)
分片列。例如,对user ID使用modulo操作来分割表,分片列是user ID,它还支持多个分片列。注意:如果查询SQL中没有分片列,那么所有表将被路由到性能较差的所有数据节点
二、分片算法(Sharding Algorithm)
(1.1)精确切分算法(Precise sharding algorithm)
用于在SQL中处理 =和IN 单个分片列,并与StandardShardingStrategy 一起使用。
(1.2)范围切分算法(Range sharding algorithm)
用于在SQL中处理 BETWEEN 单个分片列,并与StandardShardingStrategy 一起使用。
(1.3)复杂的钥匙切分算法(Complex keys sharding algorithm)
用于处理=、IN和BETWEEN的多个分片列,并与ComplexShardingStrategy 一起使用。
(1.4)提示切分算法(Hint sharding algorithm)
用来提示分片,并与HintShardingStrategy一起使用。
三、分片策略(Sharding Strategy)
3.1 精确切分策略(Standard sharding strategy)
支持 =、IN、BETWEEN在 SQL中使用单个分片列。它提供了PreciseShardingAlgorithm和RangeShardingAlgorithm,PreciseShardingAlgorithm是必需的,用于处理=和IN。RangeShardingAlgorithm是可选的,用于处理BETTWEN,如果没有,则不会触发分片,只需要路由到所有的数据节点。
3.2 复杂的分片策略(Complex sharding strategy)
支持=,IN、BETWEEN之间在SQL中有多个分片列,由于具有多个分片列的复杂性,最终用户需要自己处理。
3.3 (内联分片策略) Inline sharding strategy
仅对单个分片列使用groovy表达式,支持 =和IN sharding在SQL中。对于简单的分片算法,请使用内联表达式来避免java代码。例如:t_user_${u_id % 8}表示表t_user sharding by u_id,表附录的结果是u_id mod 8,实际表的名称从t_user_0到t_user_7。
3.4 (提示分片策略)Hint sharding strategy
使用提示而不是SQL来指示分片结果。
四、采用精确切分算法实现分库分表
/**
* 数据源配置
*/
@Configuration
@MapperScan(basePackages = "com.example.demo.mapper", sqlSessionTemplateRef = "testSqlSessionTemplate")
public class DataSourceConfig {
@Bean(name = "shardingDataSource")
DataSource getShardingDataSource() throws SQLException {
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
shardingRuleConfig.getTableRuleConfigs().add(getUserTableRuleConfiguration());
//如果有多个表,可以用逗号“,”分隔 ,比如user_info,t_order
shardingRuleConfig.getBindingTableGroups().add("user_info");
//设置分片策略,自定义算法来实现分片规则
shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_id", new DemoDatabaseShardingAlgorithm()));
shardingRuleConfig.setDefaultTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_id", new DemoTableShardingAlgorithm()));
return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig,new ConcurrentHashMap(), new Properties());
}
/**
* 配置表规则
* @return
*/
@Bean
TableRuleConfiguration getUserTableRuleConfiguration() {
TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
//配置表名
orderTableRuleConfig.setLogicTable("user_info");
//配置真实的数据节点,即数据库中真实存在的节点,由数据源名 + 表名组成
orderTableRuleConfig.setActualDataNodes("user_${0..1}.user_info_${0..1}");//user_${0..1}分库,user_info_${0..1}分表
//主键生成列,默认的主键生成算法是snowflake
orderTableRuleConfig.setKeyGeneratorColumnName("user_id");
return orderTableRuleConfig;
}
/**
* 创建数据源
* @return
*/
private Map createDataSourceMap() {
Map result = new HashMap<>();
result.put("user_0", createDataSource("user_0"));
result.put("user_1", createDataSource("user_1"));
return result;
}
/**
* 创建数据源
* @param dataSourceName
* @return
*/
private DataSource createDataSource(final String dataSourceName) {
DruidDataSource datasource = new DruidDataSource();
datasource.setDriverClassName(com.mysql.jdbc.Driver.class.getName());
datasource.setUrl(String.format("jdbc:mysql://localhost:3306/%s", dataSourceName));
datasource.setUsername("root");
datasource.setPassword("123456");
return datasource;
}
/**
* 需要手动配置事务管理器
*
* @param shardingDataSource
* @return
*/
@Bean
public DataSourceTransactionManager transactitonManager(DataSource shardingDataSource) {
return new DataSourceTransactionManager(shardingDataSource);
}
@Bean
@Primary
public SqlSessionFactory sqlSessionFactory(DataSource shardingDataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(shardingDataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
return bean.getObject();
}
@Bean
@Primary
public SqlSessionTemplate testSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
自定义分库算法实现类:DemoDatabaseShardingAlgorithm
public class DemoDatabaseShardingAlgorithm implements PreciseShardingAlgorithm {
@Override
public String doSharding(Collection collection, PreciseShardingValue preciseShardingValue) {
for (String each : collection) {
if (each.endsWith(Long.parseLong(preciseShardingValue.getValue().toString()) % 2+"")) {
return each;
}
}
throw new IllegalArgumentException();
}
}
自定义分表算法实现类:DemoTableShardingAlgorithm
public class DemoTableShardingAlgorithm implements PreciseShardingAlgorithm {
@Override
public String doSharding(Collection collection, PreciseShardingValue preciseShardingValue) {
for (String each : collection) {
if (each.endsWith(Long.parseLong(preciseShardingValue.getValue().toString()) % 2+"")) {
return each;
}
}
throw new IllegalArgumentException();
}
}
需要创建数据库user_0,user_1。
user_0数据库创建表:user_info_0,user_info_1。
user_1数据库创建表:user_info_0,user_info_1。
测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
public static Long userId = 600L;
@Resource
UserInfoMapper userInfoMapper;
@Test
public void demo() {
for (int i = 1; i <= 30; i++) {
UserInfo userInfo = new UserInfo();
userInfo.setUserId(userId);
userInfo.setAccount("Account" + i);
userInfo.setPassword("pass" + i);
userInfo.setUserName("name" + i);
userId++;
if(i==3){
HintManagerHolder.clear();
HintManager hintManager = HintManager.getInstance();
hintManager.addDatabaseShardingValue("user_info", "user_id", 3L);
hintManager.addTableShardingValue("user_info", "user_id", 3L);
System.out.println(userId);
}
userInfoMapper.insert(userInfo);
}
}
}