MYBATIS-mybatis批量插入返回主键ID报错

解决MyBatis批量插入数据时,配合spring-boot-mybatis-rw插件使用,无法正确获取自增主键ID的问题。通过调整策略,采用单条插入汇总主键ID的方法,确保数据一致性。

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

问题

使用mybatis进行批量插入的时候,并且数据库设置的是主键递增,并且在插入的时候需要返回主键id的时候,报null错误。也就是查询不到刚刚插入到数据库的id。

背景:

springboot+mbatis+插件spring-boot-mybatis-rw
关于插件spring-boot-mybatis-rw 是做什么的,请见博客https://blog.youkuaiyun.com/lifen0908/article/details/102897422

解决方案

批量插入代码

int batchInsert(@Param("records") List<BatchConf> list);
 <insert id="batchInsert"  useGeneratedKeys="true" keyProperty="id"  parameterType="java.util.List">
        insert into batch_conf (
        url,
        title,
        keywords,
        create_time,
        update_time)
        values
        <foreach collection="records" item="record" separator=",">
            ( 
            #{record.url,jdbcType=VARCHAR},
            #{record.title,jdbcType=VARCHAR},
            #{record.keywords,jdbcType=VARCHAR},
            #{record.createTime,jdbcType=TIMESTAMP},
            #{record.updateTime,jdbcType=TIMESTAMP})
        </foreach>
    </insert>

在mybatis中,假如没有插件spring-boot-mybatis-rw ,那么按照上面的写法,在xml中加入了useGeneratedKeys=“true” keyProperty=“id” 是可以返回主键了。但是加入了插件,就变成了插入数据到主库,但是查询主键id是在从库,导致在从库中查询不出来id。

不能改变项目的结构,那么就改成思路。

  1. 批量返回不了主键id,那就单条的进行插入,然后汇总得到主键ids。

  2. 先不加useGeneratedKeys=“true” keyProperty=“id”。也就是直接批量插入数据库,然后根据是插入了数据库的n条,再从数据库中查询id为前n的id的记录。这样直接分开写了,由一个批量插入变成了批量插入+查询前n条刚刚插入的数据的ids。

### MyBatis-Plus 的工作原理与实现机制 MyBatis-Plus 是一款基于 MyBatis 的增强工具,在 MyBatis 基础之上仅做增强不做改变,为简化开发、提高效率而生。以下是对其工作原理和内部机制的深入分析: --- #### 1. **核心功能概述** MyBatis-Plus 提供了许多开箱即用的功能,例如分页查询、条件构造器、逻辑删除、乐观锁等。这些功能的实现依赖于底层的拦截器机制以及对 MyBatis 功能的封装。 - **分页查询** MyBatis-Plus 的分页功能通过拦截 SQL 语句并动态修改其行为来实现。具体来说,当接收到分页请求时,会先生成一条 `COUNT` 查询以统计总记录数,然后再生成带有 `LIMIT` 和 `OFFSET` 的分页查询语句[^4]。 - **条件构造器** 条件构造器(Wrapper)是 MyBatis-Plus 提供的一种链式 API,用于构建复杂的查询条件。它将用户的业务逻辑抽象为一组标准的方法调用,并最终将其转换为对应的 SQL 片段。 - **逻辑删除** 逻辑删除是指不真正从数据库中移除数据,而是通过设置某个字段的状态值标记该条记录已被删除。MyBatis-Plus 在执行增删改查操作前,会对指定字段进行判断,从而实现逻辑上的删除效果[^2]。 - **乐观锁** 乐观锁通常利用版本号控制并发冲突。MyBatis-Plus 提供了内置的支持,能够在更新操作时验证版本号是否匹配,如果不匹配则抛出异常提示用户重试。 --- #### 2. **自动填充机制** 为了减少重复代码,MyBatis-Plus 支持字段的自动填充功能。开发者可以通过在实体类中标记需要自动填充的字段及其策略(如创建时间、更新时间),并在插入或更新数据之前由框架自动完成赋值操作[^3]。 此功能的具体实现在于 MyBatis 的拦截器机制。每当触发插入或更新操作时,拦截器会捕获到相关事件并对符合条件的字段按照预设规则进行处理。 --- #### 3. **SQL 拦截器的作用** MyBatis-Plus 广泛使用了 MyBatis 的插件机制(Interceptor)。所有的高级特性几乎都离不开拦截器的帮助。以下列举几个典型的应用场景: - **分页拦截器** 分页功能的核心在于拦截原始 SQL 并对其进行改造,加入 `LIMIT` 和 `OFFSET` 子句以便提取指定范围的数据集。同时还会额外发起一次 `COUNT(*)` 查询用来获取总的记录数量[^4]。 - **逻辑删除拦截器** 当启用了逻辑删除选项后,每次查询都会附加过滤条件排除已标记为“已删除”的记录;而在执行删除动作时,则改为更新对应列而非彻底清除整行数据。 - **乐观锁拦截器** 更新过程中校验当前记录的版本号是否等于预期值,只有相等的情况下才允许继续提交事务。否则报错告知客户端重新尝试同步最新状态后再操作。 --- #### 4. **源码结构剖析** ##### (1)BaseMapper 接口 `BaseMapper<T>` 是 MyBatis-Plus 提供给用户的最基础 DAO 层接口,已经实现了常见的 CRUD 方法无需手写任何 Mapper XML 文件就能直接调用[^2]。 ```java public interface BaseMapper<T> extends Mapper<T> { int insert(T entity); // 插入单条记录 T selectById(Serializable id); // 根据 ID 查找对象 List<T> selectBatchIds(Collection<? extends Serializable> ids); // 批量根据ID查找列表 boolean updateById(T entity); // 修改单条记录 boolean deleteById(Serializable id); // 删除单条记录 } ``` ##### (2)GlobalConfiguration 类 全局配置管理类负责存储一些影响整个项目的参数设定,像默认的主键生成策略、租户隔离模式开关等均在此处定义。 ##### (3)MetaObjectHandler 抽象类 如果希望定制化某些特殊需求可以继承此类覆写相应方法来自定义处理器的行为逻辑,比如日期格式转化或者加密算法应用等。 --- #### 5. **总结** 综上所述,MyBatis-Plus 不仅仅是对原生态 MyBatis 的简单包装,更是站在巨人的肩膀上去探索更多可能性的一次大胆创新实践成果展示。凭借高度可扩展性和易用性的完美平衡赢得了众多开发者的青睐。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值