shardingsphere批量插入,数据库主键和分布式自增键递增顺序不一致
- 问题复现和排查过程
- 版本相关
- 关键词
- 使用背景
- bug分析
- 进入debug调试
问题复现和排查过程
版本相关
shardingsphere版本:4.1.1
mybatis版本:3.5.3
关键词
mybatis、shardingsphere、sharding-jdbc、shardingjdbc、批量插入、自增主键、分布式主键、排序不一致、desc、递增
使用背景
- 使用
INSERT INTO *** VALUES \<foreach> *** \</foreach>
批量插入数据 - 使用
mysql
的自增主键unique_id
- 使用
SNOWFLAKE
自动生成分布式唯一id,但是这个id和自增主键不是同一个字段 - 数据库表
CREATE TABLE
t_user_praise_
(id
bigint(20) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘文章点赞表的id或者评论回复点赞表的id’,article_id
bigint(20) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘文章id’,record_id
bigint(20) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘文章id或者评论id或者回复id’,praise_type
tinyint(3) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘点赞类型(1-点赞文章;2-点赞评论;3-点赞回复)’,user_id
bigint(20) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘用户id’,praise_status
tinyint(3) unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘点赞状态(0-点赞;1-取消点赞)’,unique_id
bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ‘主键id’,
PRIMARY KEY (unique_id
),
UNIQUE KEYUIDX_UID_RID_TYPE
(user_id
,record_id
),
KEYIDX_ID
(id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=‘我点赞的文章、评论、回复,按用户id分库’
- 配置文件
<bean:properties id="properties">
<prop key="worker.id">123</prop>
</bean:properties>
<sharding:key-generator id="itemKeyGenerator" type="SNOWFLAKE" column="id" props-ref="properties" />
<sharding:inline-strategy id="t_user_praise_db" sharding-column="user_id" algorithm-expression="ds$->{user_id % 2}"/>
<sharding:inline-strategy id="t_user_praise_tb" sharding-column="user_id" algorithm-expression="t_user_praise_$->{user_id % 3}"/>
<sharding:table-rule logic-table="t_user_praise_" actual-data-nodes="ds$->{0..1}.t_user_praise_$->{0..2}"
database-strategy-ref="t_user_praise_db" key-generator-ref="itemKeyGenerator" table-strategy-ref="t_user_praise_tb"/>
- 插入的代码
@Transactional
@Override
public void test() {
UserPraise u1 = new UserPraise();
u1.setArticleId(1L);
u1.setRecordId(1L);
u1.setPraiseType(1);
u1.setUserId(1L);
u1.setPraiseStatus(1);
UserPraise u2 = new UserPraise();
u2.setArticleId(1L);
u2.setRecordId(2L);
u2.setPraiseType(1);
u2.setUserId(1L);
u2.setPraiseStatus(1);
List<UserPraise> uus = new ArrayList<>();
uus.add(u1);
uus.add(u2);
insertBatch(uus);
}
private void insertBatch( List<UserPraise> uus ) {
userPraiseMapper.insertBatch(uus);
}
- mybatis的xml文件
<insert id="insertBatch">
INSERT INTO t_user_praise_ ( article_id,record_id,praise_type,user_id, praise_status)
VALUES
<foreach collection="lists" item="item" separator=",">
(#{item.articleId},#{item.recordId},#{item.praiseType},#{item.userId},#{item.praiseStatus})</foreach>
</insert>
- pom文件
<!--分库分表-->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>${sharding-jdbc}</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>${sharding-jdbc}</version>
</dependency>
<!--分库分表-->
- 执行插入语句后的结果
bug分析
上述插入第一条记录id的值为
582575377823019009
,自增主键unique_id的值为1
第二条id的值为582575377823019008
,自增主键unique_id的值为2
很明显,自增unique_id为1
的记录的由SNOWFLAKE
生成的id竟比unique_id为2
的要大,按道理,他们的顺序应该是一样的。这就很奇怪了,于是,我便试图找出为什么。。。
进入debug调试
由图1可知,确实为column为id的列生成了2个id
582590044029038593
和582590044029038594
,并且大小是由小到大
在组装sql语句之前,图2看起来也都正常
但是图3的时候,第一次就获取了比较大的那个generatedValue
让我们倒回去再看看
图4看起来没啥问题,获取迭代器的next的值,肯定是从小到大按顺序获取啊。。。这。。。
再往上研究下
真实柳暗花明又一村,原来这边使用了一个
descendingIterator
,这个就会导致使用迭代器获取数据的时候,按照desc降序来回去!
那我就不禁疑问了,这是坐着有意为之,还是。。。
于是,我又去github上苦苦找寻了一番。。。真相,就在下面
看来已经有人反馈过类似的问题了,这个在旧版本是存在的,但是新版本
5.0.0-alpha
已经修复。只可惜这种问题,不怎么好用语言去描述,不然应该很容易就找到。我花了大半天时间才弄清原有并且在github上找到类似问题。。。555555555555ps:shardingsphere的
5.0.0-alpha
版本的pom坐标 和4.1.1
以及以下的版本是不一样的,所以修改版本号的时候不仅仅要修改version
。这一点我也被坑了好久好久o(╥﹏╥)o。。。另,附上github相关链接