Mybatis-Plus save和saveBatch方法忽略自增主键详解
作者:duchx
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
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
