java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Mybatis-Plus save和saveBatch方法忽略自增主键

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

作者: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

总结

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

您可能感兴趣的文章:
阅读全文