MyBatis-Plus 主键回填失效问题

 更新时间:2026年06月21日 11:03:07   作者:程序员牧羊  
本文总结了MyBatis-Plus主键回填失效的常见原因及对应解决方法,包括实体类配置、主键字段不匹配、继承冲突、自定义MapperXML、事务回滚等场景,通过详细示例代码与配置建议,帮助开发者有效解决主键回填问题

1. 问题概述

MyBatis-Plus 主键回填失效是开发中常见的问题,主要表现为插入数据后无法获取到数据库自动生成的主键值。本文详细梳理了各种失效场景及对应的解决方案。

2. 主键回填失效的常见情况

2.1 实体类主键字段未正确配置 @TableId 注解

问题描述: 实体类中的主键字段没有使用 @TableId 注解,MyBatis-Plus 无法识别哪个字段是主键。

示例代码:

// 错误示例
public class User {
    private Long id;  // 没有 @TableId 注解
    private String name;
}

// 正确示例
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
}

解决方案: 在主键字段上添加 @TableId 注解,并指定正确的 IdType

2.2 主键字段名与数据库列名不匹配

问题描述: 实体类主键字段名与数据库主键列名不一致,且未指定 value 属性。

示例代码:

// 错误示例 - 数据库列名是 user_id,实体字段是 id
@TableId(type = IdType.AUTO)
private Long id;  // 数据库列名是 user_id

// 正确示例
@TableId(value = "user_id", type = IdType.AUTO)
private Long id;

解决方案:@TableId 注解中指定 value 属性,映射到正确的数据库列名。

2.3 继承父类时主键注解冲突

问题描述: 子类继承父类,父类已定义主键注解,子类需要不同的主键字段。

示例代码:

// 父类
public class BaseModel {
    @TableId(type = IdType.AUTO)
    private Long id;  // 父类主键
}

// 子类 - 需要不同的主键字段
public class WarnRule extends BaseModel {
    private Long ruleId;  // 实际的主键字段
    // 其他字段...
}

解决方案:

  1. 方案一: 在子类中重新定义主键注解
public class WarnRule extends BaseModel {
    @TableId(value = "rule_id", type = IdType.AUTO)
    private Long ruleId;
    
    // 忽略父类的主键字段
    @TableField(exist = false)
    private Long id;
}
  1. 方案二: 使用自定义 Mapper XML 覆盖 insert 方法
<insert id="insert" parameterType="com.example.WarnRule" 
        useGeneratedKeys="true" keyProperty="ruleId" keyColumn="rule_id">
    INSERT INTO warn_rule (dict_id, rule_name, status, create_by, create_time)
    VALUES (#{dictId}, #{ruleName}, #{status}, #{createBy}, NOW())
</insert>

2.4 数据库表主键不是自增类型

问题描述: 数据库表主键不是自增类型(AUTO_INCREMENT),但实体类配置了 IdType.AUTO

示例代码:

// 错误示例 - 数据库主键不是自增
@TableId(type = IdType.AUTO)
private Long id;  // 但数据库表主键不是 AUTO_INCREMENT

解决方案:

  1. 修改数据库表结构:
ALTER TABLE your_table MODIFY COLUMN id BIGINT AUTO_INCREMENT PRIMARY KEY;
  1. 或者使用其他 IdType:
@TableId(type = IdType.INPUT)  // 手动输入
private Long id;

@TableId(type = IdType.ASSIGN_ID)  // 雪花算法
private Long id;

2.5 使用自定义 insert 方法但未配置主键回填

问题描述: 在 Mapper XML 中自定义了 insert 方法,但未配置主键回填。

示例代码:

<!-- 错误示例 - 没有配置主键回填 -->
<insert id="insert" parameterType="com.example.User">
    INSERT INTO user (name, age) VALUES (#{name}, #{age})
</insert>
<!-- 正确示例 -->
<insert id="insert" parameterType="com.example.User" 
        useGeneratedKeys="true" keyProperty="id" keyColumn="id">
    INSERT INTO user (name, age) VALUES (#{name}, #{age})
</insert>

解决方案: 在自定义 insert 中添加主键回填配置。

2.6 数据库驱动不支持主键回填

问题描述: 某些数据库驱动不支持主键回填功能。

解决方案: 检查并更新数据库驱动版本,或使用其他方式获取主键。

2.7 事务回滚导致主键丢失

问题描述: 在事务中插入数据后,如果事务回滚,主键值可能丢失。

示例代码:

@Transactional
public void saveUser() {
    User user = new User();
    user.setName("test");
    userMapper.insert(user);
    // 如果这里抛出异常,事务回滚,user.getId() 可能为 null
    System.out.println(user.getId());  // 可能为 null
}

解决方案: 确保在事务提交前使用主键值,或使用编程式事务管理。

3. 完整的解决方案

3.1 标准配置方案

@Entity
@TableName("user")
public class User {
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    
    private String name;
    private Integer age;
    
    // getter/setter...
}

3.2 继承场景解决方案

// 父类 - 不定义主键
public class BaseModel {
    private String createBy;
    private Date createTime;
    private String updateBy;
    private Date updateTime;
    // 其他公共字段...
}

// 子类 - 定义自己的主键
public class WarnRule extends BaseModel {
    @TableId(value = "rule_id", type = IdType.AUTO)
    private Long ruleId;
    
    private Long dictId;
    private String ruleName;
    // 其他字段...
}

3.3 自定义 Mapper XML 方案

<insert id="insert" parameterType="com.example.WarnRule" 
        useGeneratedKeys="true" keyProperty="ruleId" keyColumn="rule_id">
    INSERT INTO warn_rule (
        dict_id, rule_name, status, create_by, create_time, update_by, update_time
    ) VALUES (
        #{dictId}, #{ruleName}, #{status}, #{createBy}, NOW(), #{updateBy}, NOW()
    )
</insert>

3.4 编程式主键获取方案

@Service
public class UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    public Long saveUser(User user) {
        // 方案1:使用 MyBatis-Plus 的 insert 方法
        userMapper.insert(user);
        return user.getId();
        
        // 方案2:使用自定义方法
        // userMapper.insertWithKey(user);
        // return user.getId();
    }
}

4. 调试和验证

4.1 开启 MyBatis-Plus 日志

# application.yml
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

4.2 验证主键回填

@Test
public void testInsertWithKey() {
    User user = new User();
    user.setName("test");
    user.setAge(25);
    
    userMapper.insert(user);
    
    // 验证主键是否回填
    assertNotNull(user.getId());
    System.out.println("Generated ID: " + user.getId());
}

5. 最佳实践建议

  1. 统一主键策略: 在项目中统一使用一种主键生成策略
  2. 避免继承冲突: 谨慎使用继承,避免主键注解冲突
  3. 测试验证: 在开发过程中及时测试主键回填功能
  4. 文档记录: 记录项目中的主键配置规则,便于团队协作
  5. 版本兼容: 注意 MyBatis-Plus 版本升级可能带来的配置变化
    1.

6. 常见错误排查清单

  • 实体类主键字段是否有 @TableId 注解
  • @TableId 注解的 value 属性是否正确
  • 数据库表主键是否为自增类型
  • 是否使用了自定义 insert 方法
  • 自定义 insert 是否配置了主键回填
  • 数据库驱动是否支持主键回填
  • 是否在事务中正确使用主键值

通过以上详细的梳理和解决方案,应该能够解决大部分 MyBatis-Plus 主键回填失效的问题。

到此这篇关于MyBatis-Plus 主键回填失效问题的文章就介绍到这了,更多相关MyBatis-Plus 主键回填失效内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • RabbitMQ高级应用之消费端限流策略basicQos详解

    RabbitMQ高级应用之消费端限流策略basicQos详解

    这篇文章主要介绍了RabbitMQ高级应用之消费端限流策略basicQos详解,高并发情况下,队列里面一瞬间就就积累了上万条数据,但是消费者无法同时处理这么多请求,这种场景下我们就需要对消费端进行限流,需要的朋友可以参考下
    2023-08-08
  • 深入理解Java中的接口

    深入理解Java中的接口

    下面小编就为大家带来一篇深入理解Java中的接口。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-05-05
  • Java ClassLoader类加载器基础详解

    Java ClassLoader类加载器基础详解

    这篇文章主要为大家介绍了Java ClassLoader类加载器基础详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • MyBatis关于二级缓存问题

    MyBatis关于二级缓存问题

    本篇文章主要介绍了MyBatis关于二级缓存问题,二级缓存是Mapper级别的缓存,多个sqlSession操作同一个Mapper,其二级缓存是可以共享的。
    2017-03-03
  • java利用Calendar类打印日历

    java利用Calendar类打印日历

    这篇文章主要为大家详细介绍了java利用Calendar类打印日历,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07
  • idea如何自动生成Dao,mapper,pojo类

    idea如何自动生成Dao,mapper,pojo类

    文章介绍了自动生成Daomapperpojo类的过程,包括需要的两个配置文件db.properties和generatorConfig.xml,以及在pom.xml中添加依赖,最后,通过双击某个文件,控制台出现success即可生成所需类
    2026-03-03
  • Java程序打包常见几种方式的完整步骤(Maven/Gradle/ 手动打包)

    Java程序打包常见几种方式的完整步骤(Maven/Gradle/ 手动打包)

    这篇文章主要介绍了Java程序打包常见几种方式(Maven/Gradle/手动打包)的相关资料,文中通过示例代码讲解了基础方法、Maven项目打包、Gradle项目打包、打包成EXE或原生应用,需要的朋友可以参考下
    2025-12-12
  • JUnit5相关内容简介

    JUnit5相关内容简介

    这篇文章主要介绍了JUnit5相关内容简介,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • Java项目日志脱敏解决方案

    Java项目日志脱敏解决方案

    为了保护客户的敏感信息,我们提出了四种日志脱敏处理方案,需要根据实际项目需求和情况进行选择,新项目或重构的项目,对于项目标准化要求较高的,推荐使用方案四,感兴趣的朋友参考下本文
    2024-10-10
  • SpringBoot拦截器实现API安全验证的示例详解

    SpringBoot拦截器实现API安全验证的示例详解

    在开放平台和第三方集成的项目中,如何确保 API 调用的安全性和可靠性是一个重要课题,本文将详细介绍如何基于 Spring Boot 拦截器和 HMAC-SHA256 算法,构建一套轻量级但足够安全的 API 验签机制,希望对大家有所帮助
    2025-11-11

最新评论