Spring Boot中整合Sharding-JDBC單庫分表示例
在我《Spring Cloud微服務-全棧技術與案例解析》 書中都是通過XML方式配置。
今天給大家演示的是單庫中分表的操作,如果用XML方式配置,那麼就是下面的配置:
<!-- 資料來源 -->
<bean id="ds_0" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" primary="true">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/ds_0?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="123456" />
</bean>
<!-- algorithm-class="com.fangjia.sharding.UserSingleKeyTableShardingAlgorithm" -->
<!-- user_0,user_1,user_2,user_3 -->
<rdb:strategy id="userTableStrategy" sharding-columns="id" algorithm-expression="user_${id.longValue() % 4}"/>
<rdb:data-source id="dataSource">
<rdb:sharding-rule data-sources="ds_0">
<rdb:table-rules>
<rdb:table-rule logic-table="user" actual-tables="user_${0..3}" table-strategy="userTableStrategy"/>
</rdb:table-rules>
<rdb:default-database-strategy sharding-columns="none" algorithm-class="com.dangdang.ddframe.rdb.sharding.api.strategy.database.NoneDatabaseShardingAlgorithm"/>
</rdb:sharding-rule>
</rdb:data-source>
我們將user表分成了4個,分別是user_0,user_1,user_2,user_3,通過id取模的方式決定資料落在哪張表上面。
如果用Spring Boot方式配置自然就簡單多了,如下:
sharding.jdbc.datasource.names=ds_master
# 資料來源
sharding.jdbc.datasource.ds_master.type=com.alibaba.druid.pool.DruidDataSource
sharding.jdbc.datasource.ds_master.driver-class-name=com.mysql.jdbc.Driver
sharding.jdbc.datasource.ds_master.url=jdbc:mysql://localhost:3306/ds_0?characterEncoding=utf-8
sharding.jdbc.datasource.ds_master.username=root
sharding.jdbc.datasource.ds_master.password=123456
# 分表配置
sharding.jdbc.config.sharding.tables.user.actual-data-nodes=ds_master.user_${0..3}
sharding.jdbc.config.sharding.tables.user.table-strategy.inline.sharding-column=id
sharding.jdbc.config.sharding.tables.user.table-strategy.inline.algorithm-expression=user_${id.longValue() % 4}
●
actual-data-nodes:真實資料節點,由資料來源名 + 表名組成,以小數點分隔。多個表以逗號分隔,支援inline表示式。
● table-strategy.inline.sharding-column:分片欄位配置
● table-strategy.inline.algorithm-expression:分片演算法表示式
自定義分片演算法
在1.x版本中,單分片演算法是通過實現SingleKeyTableShardingAlgorithm,示例程式碼如下:
import java.util.Collection;
import java.util.LinkedHashSet;
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm;
import com.google.common.collect.Range;
public class UserSingleKeyTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Long> {
public String doEqualSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {
for (String each : availableTargetNames) {
System.out.println(each+"\t"+shardingValue.getValue()+"\t"+shardingValue.getValue() % 4 );
if (each.endsWith(shardingValue.getValue() % 4 + "")) {
return each;
}
}
throw new IllegalArgumentException();
}
public Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {
Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());
for (Long value : shardingValue.getValues()) {
for (String tableName : availableTargetNames) {
if (tableName.endsWith(value % 4 + "")) {
result.add(tableName);
}
}
}
return result;
}
public Collection<String> doBetweenSharding(Collection<String> availableTargetNames,
ShardingValue<Long> shardingValue) {
Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());
Range<Long> range = (Range<Long>) shardingValue.getValueRange();
for (Long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
for (String each : availableTargetNames) {
if (each.endsWith(i % 4 + "")) {
result.add(each);
}
}
}
return result;
}
}
我們這邊引入的Spring Boot Starter包是2.x的版本,在這個版本中,分片演算法的介面有調整,我們需要用到標準分片策略StandardShardingStrategy。提供對SQL語句中的=, IN和BETWEEN AND的分片操作支援。
StandardShardingStrategy只支援單分片鍵,提供PreciseShardingAlgorithm和RangeShardingAlgorithm兩個分片演算法。
PreciseShardingAlgorithm是必選的,用於處理=和IN的分片。RangeShardingAlgorithm是可選的,用於處理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND將按照全庫路由處理。
自定義一個單分片演算法:
import java.util.Collection;
import io.shardingjdbc.core.api.algorithm.sharding.PreciseShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
/**
* 自定義分片演算法
*
* @author yinjihuan
*
*/
public class MyPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
for (String tableName : availableTargetNames) {
if (tableName.endsWith(shardingValue.getValue() % 4 + "")) {
return tableName;
}
}
throw new IllegalArgumentException();
}
}
使用需要修改我們之前的配置:
sharding.jdbc.config.sharding.tables.user.actual-data-nodes=ds_master.user_${0..3}
sharding.jdbc.config.sharding.tables.user.table-strategy.standard.sharding-column=id
sharding.jdbc.config.sharding.tables.user.table-strategy.standard.precise-algorithm-class-name=com.fangjia.sharding.MyPreciseShardingAlgorithm
原始碼參考:
https://github.com/yinjihuan/spring-cloud/tree/master/fangjia-sjdbc-sharding-table-springboot
參考程式碼中測試的程式碼也寫好了,在Controller中,啟動後通過呼叫介面的方式測試資料的新增和查詢。
原文釋出時間為:2018-09-10
本文作者:尹吉歡