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

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

  • 问题复现和排查过程
    • 版本相关
    • 关键词
    • 使用背景
    • bug分析
    • 进入debug调试

问题复现和排查过程

版本相关

shardingsphere版本:4.1.1
mybatis版本:3.5.3

关键词

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

使用背景

  1. 使用 INSERT INTO *** VALUES \ *** \ 批量插入数据
  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">123prop>
    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.shardingspheregroupId>
                <artifactId>sharding-jdbc-spring-namespaceartifactId>
                <version>${sharding-jdbc}version>
            dependency>

            <dependency>
                <groupId>org.apache.shardingspheregroupId>
                <artifactId>sharding-jdbc-coreartifactId>
                <version>${sharding-jdbc}version>
            dependency>
            
  1. 执行插入语句后的结果
    shardingsphere批量插入引起的mysql主键和分布式自增键递增顺序不一致的bug_第1张图片

bug分析

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

进入debug调试

shardingsphere批量插入引起的mysql主键和分布式自增键递增顺序不一致的bug_第2张图片

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

shardingsphere批量插入引起的mysql主键和分布式自增键递增顺序不一致的bug_第3张图片

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

shardingsphere批量插入引起的mysql主键和分布式自增键递增顺序不一致的bug_第4张图片

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

让我们倒回去再看看

shardingsphere批量插入引起的mysql主键和分布式自增键递增顺序不一致的bug_第5张图片

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

shardingsphere批量插入引起的mysql主键和分布式自增键递增顺序不一致的bug_第6张图片

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

shardingsphere批量插入引起的mysql主键和分布式自增键递增顺序不一致的bug_第7张图片

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

真相,就在下面

shardingsphere批量插入引起的mysql主键和分布式自增键递增顺序不一致的bug_第8张图片
shardingsphere批量插入引起的mysql主键和分布式自增键递增顺序不一致的bug_第9张图片

看来已经有人反馈过类似的问题了,这个在旧版本是存在的,但是新版本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

你可能感兴趣的:(shardingsphere,mysql,源码分析,shardingsphere,mysql,sharding,jdbc)