前言

前面所讲的ShardingSphere分库分表及读写分离的路由规则,比如通过id分表,都是在配置文件中配置的全局生效。假设这样一种场景,我们需要在代码中根据某些业务逻辑来具体指定哪些数据该去哪些库表中,这时候我们前面的全局路由规则就不能满足要求了。这就引出了Hint的概念。

什么是Hint

在一些应用场景中,分片条件并不存在于SQL,而存在于外部业务逻辑。因此需要提供一种通过在外部 业务代码中指定路由配置的一种方式,在ShardingSphere中叫做Hint。如果使用Hint指定了强制分片 路由,那么SQL将会无视原有的分片逻辑,直接路由至指定的数据节点操作。

数据准备

city表分别存在lagou1及lagou2两个库中,sql如下:

1
2
3
4
5
6
CREATE TABLE `city` (
`Id` bigint(11) NOT NULL AUTO_INCREMENT,
`name` varchar(256) DEFAULT NULL,
`province` varchar(256) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

两个库中city的数据如下图:

代码及配置

实体类及JPA相关代码见文末源码,在此不做赘述。

配置文件中配置数据源及hint对应的分片实现类的全路径:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#datasource
spring.shardingsphere.datasource.names=ds0,ds1

spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://localhost:3306/lagou1
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=000

spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://localhost:3306/lagou2
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=000

#hint
spring.shardingsphere.sharding.tables.city.database-strategy.hint.algorithm-class-name=com.lagou.hint.MyHintShardingAlgorithm

HintShardingAlgorithm实现类来配置分片策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.lagou.hint;

public class MyHintShardingAlgorithm implements HintShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(
Collection<String> availableTargetNames,
HintShardingValue<Long> shardingValue) {
Collection<String> result = new ArrayList<>();
for (String each : availableTargetNames){
for (Long value : shardingValue.getValues()){
//availableTargetNames是ds0,ds1
//shardingValue是传入的long型整数
if(each.endsWith(String.valueOf(value % 2))){
result.add(each);
}
}
}
return result;
}
}

测试

1
2
3
4
5
6
7
8
9
@Test
public void test1(){
HintManager hintManager = HintManager.getInstance();
hintManager.setDatabaseShardingValue(0L); //强制路由到ds${xx%2}
List<City> list = cityRepository.findAll();
list.forEach(city->{
System.out.println(city.getId()+" "+city.getName()+" "+city.getProvince());
});
}

debug可以看到分片策略中的变量:

结果打印如下:

源码

sharding-jdbc之Hint强制路由