现象
在同一个库中,将一张表分成多张,在xml中使用如下的语法:
<foreach collection="params" item="item" separator=";">
update table_hello set column_hello = #{item.itemHello} where sharding_key = #{item.shardingKey}
</foreach>
PreciseShardingAlgorithm:
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> shardingValue) {
Long value = doSharding(shardingValue.getValue());
for (String each : availableTargetNames) {
if (each.endsWith(value % 16 + "")) {
return each;
}
}
return null;
}
根据主观臆想,生成每条sql的时候,sharding sphere都会帮我们替换一下表名,但是跑起来的时候将会直接出错,报出表名不存在的错误,
根据log打印出来的真实sql来看,例如有三条更新语句,只有第一条
被替换成了真实的表名,其他的没有被替换,
这点经过验证,官方给出的回复是,因为虽然有多条语句,但是这只是同一次sql请求,因此他们不支持这么做,只会将第一个表名替换掉,
这么做我想可能是有一定的考量的,比如路由的键值有很多,可能会同一次请求有很多不同的路由,甚至如果分库了可能会路由到不同的库中,所以官方限制了这个使用。
官方回复:https://github.com/apache/shardingsphere/issues/6665
解决方式
前提:保证多条update语句的路由键值是同一个,保证路由的统一性,
在循环sql中,根据路由规则动态生成表名,这需要mybatis中调用生成路由key的类和方法:
<foreach collection="params" item="item" separator=";">
update table_hello set column_hello = #{item.itemHello_${@java包路径.类名@生成路由key方法(item.key参数)}} where sharding_key = #{item.shardingKey}
</foreach>
我们利用xml中可以动态生成表名的方式,来解决这个问题,但是最好一定要保证item.key参数
是同一个,例如更新一个订单的明细,因为一个订单号的明细的路由规则可能是根据订单号来路由的。
后记
有个很好玩的事情,当时一个同事和我用一样的写法,就是上文现象里的写法,他的是可以的,但是我的不行,
就觉得很诡异,难道官方偷偷的支持了? 后来发现并不是,我们开发的是不同的模块,
因为他用的是分库,没有分表
,多条update语句只需要路由到其中的库中,直接更新他库中的一张表就行了,
所以表名不需要被sharding sphere
替换,用原始的就好,
但是我的因为分表了, 原始表名是需要被替换的,因此出现了感觉上
这么一个奇怪的问题。