shardingsphere批量插入引起的mysql主键和分布式自增键递增顺序不一致的bug

shardingsphere批量插入,数据库主键和分布式自增键递增顺序不一致

问题复现和排查过程

版本相关

shardingsphere版本:4.1.1
mybatis版本:3.5.3

关键词

mybatis、shardingsphere、sharding-jdbc、shardingjdbc、批量插入、自增主键、分布式主键、排序不一致、desc、递增

使用背景

  1. 使用 INSERT INTO *** VALUES \<foreach> *** \</foreach> 批量插入数据
  2. 使用mysql的自增主键unique_id
  3. 使用SNOWFLAKE自动生成分布式唯一id,但是这个id和自增主键不是同一个字段
  4. 数据库表

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 KEY UIDX_UID_RID_TYPE (user_id,record_id),
KEY IDX_ID (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=‘我点赞的文章、评论、回复,按用户id分库’

  1. 配置文件
<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"/>
  1. 插入的代码
    @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);
    }
  1. 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>
  1. 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>
            <!--分库分表-->
  1. 执行插入语句后的结果
    bug

bug分析

上述插入第一条记录id的值为582575377823019009,自增主键unique_id的值为1
第二条id的值为582575377823019008,自增主键unique_id的值为2
很明显,自增unique_id为1的记录的由SNOWFLAKE生成的id竟比unique_id为2的要大,按道理,他们的顺序应该是一样的。这就很奇怪了,于是,我便试图找出为什么。。。

进入debug调试

图1

由图1可知,确实为column为id的列生成了2个id582590044029038593582590044029038594,并且大小是由小到大

图2

在组装sql语句之前,图2看起来也都正常

图3

但是图3的时候,第一次就获取了比较大的那个generatedValue

让我们倒回去再看看

图4

图4看起来没啥问题,获取迭代器的next的值,肯定是从小到大按顺序获取啊。。。这。。。
再往上研究下

图5

真实柳暗花明又一村,原来这边使用了一个descendingIterator,这个就会导致使用迭代器获取数据的时候,按照desc降序来回去!

图6

那我就不禁疑问了,这是坐着有意为之,还是。。。
于是,我又去github上苦苦找寻了一番。。。

真相,就在下面

图11
图22

看来已经有人反馈过类似的问题了,这个在旧版本是存在的,但是新版本5.0.0-alpha已经修复。只可惜这种问题,不怎么好用语言去描述,不然应该很容易就找到。我花了大半天时间才弄清原有并且在github上找到类似问题。。。555555555555

ps:shardingsphere的5.0.0-alpha版本的pom坐标 和4.1.1以及以下的版本是不一样的,所以修改版本号的时候不仅仅要修改version。这一点我也被坑了好久好久o(╥﹏╥)o。。。

另,附上github相关链接,点我
Multi-values insertion bug with key-generator in sharding databases/tables
Why do distributed primary keys need to be retrieved in reverse order in ShardingGeneratedKeyInsertValueParameterRewriter.rewrite

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值