项目需要分表分库,在网上找到了shardingsphere插件,接入过程还是蛮曲折的,今天终于有时间搞通了。sharding的介绍等会再说,还是直接上代码。
一、引入jar包,我使用的v4.0.0版本
org.apache.shardingsphere
sharding-jdbc-core
${sharding-sphere.version}
org.apache.shardingsphere
sharding-jdbc-spring-namespace
${sharding-sphere.version}
二、因为是SpringMVC,所以采用基于Spring命名空间的规则配置,具体配置如下:
classpath*:mapper/*.xml
classpath*:mapper/**/*.xml
helperDialect=mysql
我是采用StandardShardingStrategy,标准分片策略提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。RangeShardingAlgorithm是可选的,用于处理BETWEEN AND, >, <, >=, <=分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。
重写了精准分片算法和范围分片算法。具体代码如下:
/**
* 精准分表算法
* @author chuhx
* @date 2020/3/6 11:48
**/
@Component
public class ShardingTableAlgorithm implements PreciseShardingAlgorithm {
@Override
public String doSharding(Collection tableNames, PreciseShardingValue preciseShardingValue) {
String tableName = "tb_order";
if(preciseShardingValue.getValue()==null){
return tableName;
}
tableName = Lists.newArrayList(tableNames).get(0);
String sdValue = DateUtils.format(preciseShardingValue.getValue(),"yyyyMMddHHmmss");
if(StringUtils.isBlank(sdValue)){
return tableName;
}
return tableName+sdValue.substring(0,6);
}
}
/**
* 范围分表算法
* @author chuhx
* @date 2020/3/9 17:07
**/
public class ShardingRangTableAlgorithm implements RangeShardingAlgorithm {
/**
* Sharding.
*
* @param availableTargetNames available data sources or tables's names
* @param shardingValue sharding value
* @return sharding results for data sources or tables's names
*/
@Override
public Collection doSharding(Collection availableTargetNames, RangeShardingValue shardingValue) {
String tableName = "tb_order";
Range range = shardingValue.getValueRange();
Date startDate = range.lowerEndpoint();
Date endDate = range.upperEndpoint();
if(endDate.after(new Date())){
endDate = new Date();
}
Set dateSet = new HashSet<>();
dateSet.add(tableName);
for(;startDate.before(endDate);startDate = DateUtils.dateAdd(DateUtils.DATE_INTERVAL_DAY,startDate,1)){
String sdValue = DateUtils.format(startDate,"yyyyMMddHHmmss");
if(StringUtils.isNotBlank(sdValue) && sdValue.length()>6){
dateSet.add(tableName+sdValue.substring(0,6));
}
}
return dateSet;
}
}
OK,这样就全部代码,接下来可以写方法进行测试。由于是根据支付时间分表的,直接写个简单查询。
/**
* 根据支付时间查询订单
* @param payStartDate
* @param payEndDate
* @return
*/
List selectOrderListByPayAt1(@Param("payStartDate") Date payStartDate, @Param("payEndDate") Date payEndDate);
@ResponseBody
@RequestMapping(value = "/test",method = RequestMethod.GET)
public String sendMsgToKafka(){
Date endDate = new Date();
Date startDate = DateUtils.dateAdd(DateUtils.DATE_INTERVAL_DAY,endDate,-30);
List order = orderMapper.selectOrderListByPayAt1(startDate,endDate);
return JSON.toJSONString("订单信息="+JSON.toJSONString(order));
}
可以直接运行一切OK。
三、接入遇到的坑
1、最开始我接入的时候,没有指定实际数据表,运行时一致报错有两个数据源。最后检查了半天是这个问题。
2、由于是按照时间分片,需要按照范围查找的,所有又重写了范围分片算法。
3、可以写个定时任务每月建一张表。
4、把事务等数据源都改为:shardingDataSource
四、结论
在引入第三方插件时,建议仔细看官方文档和源码,不要病急乱投医。不是有句古话:磨刀不如砍柴工。别人的东西是挺省事,关键是要适合自己。特此记录下来,供以后学习参考,方便自己与方便他人,何乐而不为!