因为在项目中,需要用到分库,但不分表。网上找到sharding-jdbc组件,因为业务要求分库,而不是采用数据库字段形式,进行路由。所以需要采用:hint方式,但网上资料少的可怜,而且版本不同,实现起来略有差异,而且网上的实现,注释不全。经过3天的研究,终于了解了hint方式的用法,现在把成果贴出来,供大家参考!
maven 包引入
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>4.1.0</version>
</dependency>
修改spring配置文件(本例子采用xml配置文件配置)
<!-- 基于暗示(Hint)的分片策略 -->
<bean id="ds0" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://121.229.54.24:3306/wechat01" />
<property name="username" value="bluemine-dev" />
<property name="password" value="Qazxsw123" />
</bean>
<bean id="ds1" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://121.229.54.24:3306/wechat02" />
<property name="username" value="bluemine-dev" />
<property name="password" value="Qazxsw123" />
</bean>
<!-- 采用自定义暗示分片 -->
<sharding:hint-strategy id="hintDatabaseShardingStrategy" algorithm-ref="myHintStrategy"/>
<!-- 定义数据源 -->
<sharding:data-source id="dataSource">
<sharding:sharding-rule data-source-names="ds0, ds1">
<sharding:table-rules>
<sharding:table-rule logic-table="t_order" actual-data-nodes="ds$->{0..1}.t_order$->{0..1}" database-strategy-ref="hintDatabaseShardingStrategy" table-strategy-ref="hintDatabaseShardingStrategy"/>
</sharding:table-rules>
</sharding:sharding-rule>
<sharding:props>
<prop key="sql.show">true</prop>
</sharding:props>
</sharding:data-source>
注意
:当只分库不分表时,Hint 也需要指定分片表 的数据库分片算法 + 表分片算法, 这一点很不理解
。
自定义解析类
package com.bluemine.qt.task;
import com.alibaba.druid.util.StringUtils;
import org.apache.shardingsphere.api.sharding.ShardingValue;
import org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.hint.HintShardingValue;
import org.omg.CORBA.OBJ_ADAPTER;
import org.springframework.stereotype.Component;
import java.util.*;
@Component("myHintStrategy")
public class MyHintStrategy implements HintShardingAlgorithm {
/**
* 分片方法
* 会分别对 库 和 表进行路由, 库 和 表分2次进行的.
* 流程:
* 程序调用者,指定几号库: hintManager.addDatabaseShardingValue("t_order", 3); 表示:3号库,执行t_order表相关
* 框架调用: doSharding 方法:
* availableTargetNames 为:数据库列表: [ds0, ds1]
* shardingValue 为:指定的数据库
* 程序调用方,指定几号表: hintManager.addTableShardingValue("t_order", 1); 表示: 1号数据表
* 框架第二次调用doSharding 方法:
* availableTargetNames 为:数据表 列表: [t_order0, t_order1];
* shardingValue 为:指定的数据表
* 依次类推, 如果程序调用方,还有其他表的指定,则框架还好再次调用此方法.
*
* @param availableTargetNames
* @param shardingValue
* @return
*/
@Override
public Collection<String> doSharding(Collection availableTargetNames, HintShardingValue shardingValue) {
System.out.println("shardingValue=" + shardingValue);
System.out.println("availableTargetNames=" + availableTargetNames);
List<String> shardingResult = new ArrayList<>();
Iterator i = availableTargetNames.iterator();
while (i.hasNext()){
String targetName = (String) i.next();
String suffix = targetName.substring(targetName.length() - 1);
if (StringUtils.isNumber(suffix)) {
// hint分片算法的ShardingValue有两种具体类型:
// ListShardingValue和RangeShardingValue
// 使用哪种取决于HintManager.addDatabaseShardingValue(String, String, ShardingOperator,...),ShardingOperator的类型
Iterator j = shardingValue.getValues().iterator();
while (j.hasNext()){
Integer value = (Integer) j.next();
if (value % 2 == Integer.parseInt(suffix)) {
shardingResult.add(targetName);
}
}
}
}
return shardingResult;
}
}
调用入口代码(junit 用法,自行百度)
@Test
public void shardingDB() throws Exception {
HintManager.clear();
HintManager hintManager = HintManager.getInstance();
// 方式1:
// 下面2句话的意思时: 向3号库中的1号 t_order 表执行sql
// 选择具体的数据库, 3 可以简单理解为: 3号库,如果只有2个库, 那么可以根据2取模,落到 1号库上面
hintManager.addDatabaseShardingValue("t_order", 3);
// 同理:一个数据库中可以有多张t_order表, 1 可以理解为: 1号表.
hintManager.addTableShardingValue("t_order", 1);
// 方式2
// 直接指定对应具体的数据库
// hintManager.setDatabaseShardingValue(0);
Order order = new Order();
order.setUserId(2);
order.setName("测试00");
orderMapper.insert(order);
HintManager.clear();
}