Sharding Sphere JDBC使用Mybatis的saveBatch无法返回主键的问题

文章讨论了在使用MybatisPlus和ShardingSphereJDBC进行分库分表时,批量新增导致无法获取自增ID的问题。原因是ShardingSphere重写Statement导致结果未保存。提供了解决方案,包括配置多个数据源和重写ShardingSpherePreparedStatement类的addBatch方法以缓存Statement。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题背景

项目中使用了MybatisPlus框架,数据库是PostgreSQL,配置了主键自增,新增数据后返回主键到实体类中。

项目中因为数据量问题,需要用到分库分表,因此引入了Sharding Sphere JDBC框架。但是Sharding Sphere JDBC会读取sql语句,根据分库分分表规则,重新组合sql语句,到这一步还没有问题。使用Mybatis的批量新增之后,无法获取到数据库自增产生的ID,实体类中id字段为空。

原因分析

原因应该是Sharding Sphere JDBC重写了statment,没有将数据库返回的结果保存下来

这个应该是Sharding Sphere与ORM框架整合的bug

Github中有人提出这个问题,官方回答他们没人时间去阅读第三方ORM的框架代码,只对JDBC做兼容,意思就是说他们不管这个bug😂

image-20240407224533619

https://github.com/apache/shardingsphere/issues/9592

解决方案

1.配置多数据源,分表的地方使用ShardingSphere,其他表使用正常的ORM框架

2.Github大佬提供的解决办法:

通过重写ShardingSpherePreparedStatement类中的addBatch方法,将statment缓存下来

注意这个版本必须是5.2.1版本以上的才可以使用

public void addBatch() {
    try {
        QueryContext queryContext = this.createQueryContext();
        this.trafficInstanceId = this.getInstanceIdAndSet(queryContext).orElse(null);
        this.executionContext = null != this.trafficInstanceId ? this.createExecutionContext(queryContext, this.trafficInstanceId) : this.createExecutionContext(queryContext);
        this.batchPreparedStatementExecutor.addBatchForExecutionUnits(this.executionContext.getExecutionUnits());

        // 这里加一下缓存statement,cacheBatchStatements是新方法
        ExecutionGroupContext<JDBCExecutionUnit> executionGroupContext = this.createExecutionGroupContext();
        this.cacheBatchStatements(executionGroupContext.getInputGroups());
    } catch (SQLException e) {
        throw new RuntimeException(e);
    } finally {
        this.currentResultSet = null;
        this.clearParameters();
    }
}

private void cacheBatchStatements(Collection<ExecutionGroup<JDBCExecutionUnit>> executionGroups) throws SQLException {
    Iterator var2 = executionGroups.iterator();

    while(var2.hasNext()) {
        ExecutionGroup<JDBCExecutionUnit> each = (ExecutionGroup<JDBCExecutionUnit>)var2.next();
        each.getInputs().forEach((eachInput) -> {
            if (!this.statements.contains((PreparedStatement)eachInput.getStorageResource())) {
                this.statements.add((PreparedStatement)eachInput.getStorageResource());
            }
        });
    }
}
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.2.1</version>
</dependency>

github大佬地址:https://github.com/baomidou/mybatis-plus/issues/3207

ShardingSphere目前的版本(5.0.0-alpha)与之前的版本(4.1.1及以下)在pom坐标上有所不同,因此在修改版本号时不仅需要修改version,还需要注意其他相关的变化。\[1\] 关于批量更新,ShardingSphere目前不支持多条update语句的批量更新,即使多条语句也只会更新一条。\[2\]如果你需要批量更新多条数据,可以考虑使用其他方法或工具来实现。 另外,如果你在使用ShardingSphere时遇到了与mybatissharding-jdbcshardingjdbc等相关的问题,可以提供更具体的信息,以便我能够给出更准确的答案。 #### 引用[.reference_title] - *1* *3* [shardingsphere批量插入引起的mysql主键和分布式自增键递增顺序不一致的bug](https://blog.csdn.net/starryninglong/article/details/115264774)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [sharding-sphere报错总结](https://blog.csdn.net/qq_41901039/article/details/124802670)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值