记录ShardingSphere的一个坑

  • 现象

4.0.0-RC1版本,我设置了数据自动生成分布式主键ID,然后当我进行数据插入的时候,我发现其中一个字段value值是null的时候,这个自动生成的主键ID赋值错乱了。

  • 找问题

那咋办呢?只能从他的原理以及源码入手了。设置了自动生成分布式主键,那么他是怎么操作的呢?

经过一番查询和测试之后,ShardingSphere是这么做的。他拿到业务层处理的sql之后,他在这个sql上面进行了改造。举个例子,我要在user表里面插入一条数据,sql如下:

INSERT INTO user (name, remark, age) VALUES ('test', null, 18);

然后ShardingSphere会进行处理,他会在我原有的sql上加ID,然后正常得到的sql应该是:

INSERT INTO user (name, remark, age, id) VALUES ('test', null, 18, '主键id');

但是事实却是这样的:

INSERT INTO user (name, remark, age, id) VALUES ('test', 18, '主键id', null);

怎么会这样呢?看起来感觉像是最后赋值的时候null的情况判断是有问题的,那么我们接下去继续去看源码。

又是一番debug + 查找之后。。。。

发现有这样一个抽象类InsertOptimizeResultUnit,其中有一个方法是getCurrentIndex,如下图:

截屏的这一步操作是在做什么呢?他主要是查找value这个数组的最后一位的下标是多少,由于他每一次都对value进行了非空判断,也就是说只要有一个value值为空,那么这个下标计算出来就会少1。那么最后最后造成的结果就是明明他应该在age后面加上id,但是由于下标计算错误导致id的value值去覆盖了age的value值。

解决方案

首先先去github上提交了issue,地址是https://github.com/apache/incubator-shardingsphere/issues/2897

先看ShardingSphere的开发者是否已经解决了这个问题,如果他们要在后续的版本进行解决的话,目前只有两个方案解决了:

1.我只能先暂时对字段加一个默认值,尽量使value不为空(不太好)
2.将github上的代码拉下来,然后自己修改源码然后自己打一个包来用(较合适)

若有问题,欢迎一起讨论,一起学习进步!

转载于:https://my.oschina.net/u/3095034/blog/3095016

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的使用ShardingSphere实现分库分表的Java例子: 首先,需要在pom.xml文件中添加ShardingSphere的依赖: ``` <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-core</artifactId> <version>4.1.1</version> </dependency> ``` 接着,需要在Spring配置文件中添加ShardingSphere的数据源配置: ``` 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/db0?useUnicode=true&characterEncoding=utf-8 spring.shardingsphere.datasource.ds0.username=root spring.shardingsphere.datasource.ds0.password=root 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/db1?useUnicode=true&characterEncoding=utf-8 spring.shardingsphere.datasource.ds1.username=root spring.shardingsphere.datasource.ds1.password=root spring.shardingsphere.sharding.tables.user.actual-data-nodes=ds${0..1}.user_${0..1} spring.shardingsphere.sharding.tables.user.table-strategy.standard.sharding-column=user_id spring.shardingsphere.sharding.tables.user.table-strategy.standard.precise-algorithm-class-name=com.example.algorithm.ModuloShardingTableAlgorithm spring.shardingsphere.sharding.tables.user.table-strategy.standard.range-algorithm-class-name=com.example.algorithm.RangeShardingTableAlgorithm ``` 注意,上面的例子中使用了两个数据源ds0和ds1,分别对应了两个数据库db0和db1。同时,使用了ShardingSphere的分片表策略,将user表按照user_id字段进行分片,使用了ModuloShardingTableAlgorithm和RangeShardingTableAlgorithm算法来实现分片。 最后,需要实现两个算法类: ModuloShardingTableAlgorithm.java: ``` public final class ModuloShardingTableAlgorithm implements PreciseShardingAlgorithm<Integer> { @Override public String doSharding(Collection<String> tableNames, PreciseShardingValue<Integer> shardingValue) { for (String each : tableNames) { if (each.endsWith(shardingValue.getValue() % tableNames.size() + "")) { return each; } } throw new IllegalArgumentException(); } } ``` RangeShardingTableAlgorithm.java: ``` public final class RangeShardingTableAlgorithm implements RangeShardingAlgorithm<Integer> { @Override public Collection<String> doSharding(Collection<String> tableNames, RangeShardingValue<Integer> shardingValue) { Collection<String> result = new LinkedHashSet<>(); for (Integer i = shardingValue.getValueRange().lowerEndpoint(); i <= shardingValue.getValueRange().upperEndpoint(); i++) { for (String each : tableNames) { if (each.endsWith(i % tableNames.size() + "")) { result.add(each); } } } return result; } } ``` 这样,就可以使用ShardingSphere实现分库分表了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值