Mybatis-Plus save和saveBatch方法忽略自增主键详解

 更新时间:2025年12月15日 08:45:15   作者:duchx  
Mybatis-Plus在从3.4.0升级到3.5.6后,save和saveBatch方法在处理自增主键时会出现主键冲突的问题,这是因为3.5.6版本中增加了`ignoreAutoIncrementColumn`属性,默认值为false,导致在生成SQL语句时忽略了自增主键,解决方法是手动设置主键值

Mybatis-Plus save和saveBatch方法忽略自增主键

这个mybatisplus版本从3.4.0升级到3.5.6之后原来涉及到save和saveBatch方法的地方会报主键冲突

org.springframework.dao.DuplicateKeyException:
### Error updating database.  Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '*' for key '*****.PRIMARY'

各大搜索引擎搜索了一圈,都没有关于这个问题的答案,于是只能跟踪mybatisplus代码进去一探究竟

在MybatisPlusAutoConfiguration创建SqlSessionFactory对象后会

从跟踪情况得知sql语句的生成是在服务启动的时候就加载生成了的。

在MybatisConfiguration类中创建SqlSessionFactory对象

创建过程中遍历mapperLocations使用MybatisXMLMapperBuilder对Mapper文件进行解析,中间步骤跳过,因为我们跟踪的是save和saveBatch这两个方法最终调用的是Mapper.insert方法,所以只需看Insert类即可,上面解析方法为insert通过Insert类来完成

public class Insert extends AbstractMethod {
    private boolean ignoreAutoIncrementColumn;

    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
        SqlMethod sqlMethod = SqlMethod.INSERT_ONE;
        String columnScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlColumnMaybeIf((String)null, this.ignoreAutoIncrementColumn), "(", ")", (String)null, ",");
        String valuesScript = "(\n" + SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlPropertyMaybeIf((String)null, this.ignoreAutoIncrementColumn), (String)null, (String)null, (String)null, ",") + "\n" + ")";
        String keyProperty = null;
        String keyColumn = null;
        if (StringUtils.isNotBlank(tableInfo.getKeyProperty())) {
            if (tableInfo.getIdType() == IdType.AUTO) {
                keyGenerator = Jdbc3KeyGenerator.INSTANCE;
                keyProperty = tableInfo.getKeyProperty();
                keyColumn = SqlInjectionUtils.removeEscapeCharacter(tableInfo.getKeyColumn());
            } else if (null != tableInfo.getKeySequence()) {
                keyGenerator = TableInfoHelper.genKeyGenerator(this.methodName, tableInfo, this.builderAssistant);
                keyProperty = tableInfo.getKeyProperty();
                keyColumn = tableInfo.getKeyColumn();
            }
        }

        String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), columnScript, valuesScript);
        SqlSource sqlSource = super.createSqlSource(this.configuration, sql, modelClass);
        return this.addInsertMappedStatement(mapperClass, modelClass, this.methodName, sqlSource, (KeyGenerator)keyGenerator, keyProperty, keyColumn);
    }
}

这个类代码不多,只有一个方法injectMappedStatement,关键代码就在这个方法的columnScript变量赋值上面getAllInsertSqlColumnMaybeIf((String)null, this.ignoreAutoIncrementColumn)
这个方法有个传参ignoreAutoIncrementColumn,是Insert类的成员变量

这个值的默认值是false,在3.4.0的版本中是没有的

3.4.0的版本代码

public class Insert extends AbstractMethod {
    public Insert() {
    }

    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        KeyGenerator keyGenerator = new NoKeyGenerator();
        SqlMethod sqlMethod = SqlMethod.INSERT_ONE;
        String columnScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlColumnMaybeIf((String)null), "(", ")", (String)null, ",");
        String valuesScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlPropertyMaybeIf((String)null), "(", ")", (String)null, ",");
        String keyProperty = null;
        String keyColumn = null;
        if (StringUtils.isNotBlank(tableInfo.getKeyProperty())) {
            if (tableInfo.getIdType() == IdType.AUTO) {
                keyGenerator = new Jdbc3KeyGenerator();
                keyProperty = tableInfo.getKeyProperty();
                keyColumn = tableInfo.getKeyColumn();
            } else if (null != tableInfo.getKeySequence()) {
                keyGenerator = TableInfoHelper.genKeyGenerator(this.getMethod(sqlMethod), tableInfo, this.builderAssistant);
                keyProperty = tableInfo.getKeyProperty();
                keyColumn = tableInfo.getKeyColumn();
            }
        }

        String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), columnScript, valuesScript);
        SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
        return this.addInsertMappedStatement(mapperClass, modelClass, this.getMethod(sqlMethod), sqlSource, (KeyGenerator)keyGenerator, keyProperty, keyColumn);
    }
}

比3.5.6就少了这个属性,而columnScript赋值的后面方法中如果主键策略是IdType.AUTO也就是自增主键的话默认是不带主键返回的

所以如果3.4.0的版本用了save或saveBatch方法并且带了主键值升级为3.5.6后需要手动设置

mybatis-plus.global-config.db-config.insertIgnoreAutoIncrementColumn=true

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java 回调机制(CallBack) 详解及实例代码

    Java 回调机制(CallBack) 详解及实例代码

    这篇文章主要介绍了 Java 回调机制(CallBack) 详解及实例代码的相关资料,需要的朋友可以参考下
    2017-02-02
  • Java实现上传和下载功能(支持多个文件同时上传)

    Java实现上传和下载功能(支持多个文件同时上传)

    这篇文章主要介绍了Java实现上传和下载功能,支持多个文件同时上传,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • 抽象类使用Jackson序列化问题

    抽象类使用Jackson序列化问题

    这篇文章主要介绍了抽象类使用Jackson序列化问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • Java执行shell命令的实现

    Java执行shell命令的实现

    本文主要介绍了Java执行shell命令的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • Mybatis-Plus自动生成id涉及的问题解决过程

    Mybatis-Plus自动生成id涉及的问题解决过程

    文章主要讲述了解决用户ID在页面和数据库中不一致的问题,并提供了两种解决方案:将主键类型改为String或删除数据库表重新创建以清空最大id
    2025-12-12
  • Java的垃圾回收机制实例分析

    Java的垃圾回收机制实例分析

    这篇文章主要介绍了Java的垃圾回收机制,结合实例形式分析了垃圾回收机制的原理及相关操作技巧,需要的朋友可以参考下
    2019-08-08
  • java中获取hashmap中的所有key方式

    java中获取hashmap中的所有key方式

    这篇文章主要介绍了java中获取hashmap中的所有key方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • springmvc中进行数据保存以及日期参数的保存过程解析

    springmvc中进行数据保存以及日期参数的保存过程解析

    这篇文章主要介绍了springmvc中进行数据保存以及日期参数的保存过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • Java程序员应该遵守的10条纪律

    Java程序员应该遵守的10条纪律

    Java程序员有许多应遵循的守则或最佳实践方式。本文概述了每个开发者最应该遵循的10条守则或戒律,如果不遵循它们,将会导致灾难性后果。
    2015-09-09
  • 解释为什么Java中“1000==1000”为false而”100==100“为true

    解释为什么Java中“1000==1000”为false而”100==100“为true

    在日常编程中,我们经常遇到一些看似简单却隐藏着复杂逻辑的问题,这篇文章主要介绍了解释为什么Java中“1000==1000”为false而”100==100“为true,需要的朋友可以参考下
    2024-01-01

最新评论