MyBatisPlus批量插入主键被覆盖问题解决

作者 : admin 本文共4559个字,预计阅读时间需要12分钟 发布时间: 2024-06-9 共3人阅读

背景

通过MybatisPlus实现insertBatchSomeColumn接口实现真正意义上的批量插入时,数据已经准备了Id但是插入进数据库时Id被覆盖。

原因

查看源码可以发现,在处理中如果Id字段通过@TableId(type = IdType.AUTO)注解标记时,拼接的字符串会忽略Id字段的值,采用数据库自增进行填充。

@SuppressWarnings("Duplicates")
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
SqlMethod sqlMethod = SqlMethod.INSERT_ONE;
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
String insertSqlColumn = tableInfo.getKeyInsertSqlColumn(true, null, false) +
this.filterTableFieldInfo(fieldList, predicate, TableFieldInfo::getInsertSqlColumn, EMPTY);
String columnScript = LEFT_BRACKET + insertSqlColumn.substring(0, insertSqlColumn.length() - 1) + RIGHT_BRACKET;
String insertSqlProperty = tableInfo.getKeyInsertSqlProperty(true, ENTITY_DOT, false) +
this.filterTableFieldInfo(fieldList, predicate, i -> i.getInsertSqlProperty(ENTITY_DOT), EMPTY);
insertSqlProperty = LEFT_BRACKET + insertSqlProperty.substring(0, insertSqlProperty.length() - 1) + RIGHT_BRACKET;
String valuesScript = SqlScriptUtils.convertForeach(insertSqlProperty, "list", null, ENTITY, COMMA);
String keyProperty = null;
String keyColumn = null;
// 表包含主键处理逻辑,如果不包含主键当普通字段处理
if (tableInfo.havePK()) {
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, builderAssistant);
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
}
}
}
String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), columnScript, valuesScript);
SqlSource sqlSource = super.createSqlSource(configuration, sql, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, methodName, sqlSource, keyGenerator, keyProperty, keyColumn);
}

例子

有一个Task,作用是在项目启动时扫描项目中的接口(被接口注解标注)信息,通过判断是否被标记鉴权注解来进行数据库插入。所以此时Id是通过接口关系指定的,即一对多的关系。

  1. 当注解为 @TableId(type = IdType.AUTO)

SQL日志:

JDBC Connection [ConnectionProxyImpl{connectedTime=2024-06-07 16:44:15.881, closeCount=0, lastValidateTimeMillis=2024-06-07 16:44:15.887}] will not be managed by Spring
==>  Preparing: INSERT INTO sys_api (parent_id,operation,url,summary,method,status,create_time,update_time) VALUES (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?)
==>

SQL拦截:

INSERT INTO sys_api (parent_id,operation,url,summary,method,status,create_time,update_time) VALUES xxxxxx

数据库数据:

MyBatisPlus批量插入主键被覆盖问题解决插图

  1. 当注解为非@TableId(type = IdType.AUTO)时,如 @TableId(type = IdType.ASSIGN_ID)雪花Id

SQL日志:

DBC Connection [ConnectionProxyImpl{connectedTime=2024-06-07 16:47:17.421, closeCount=0, lastValidateTimeMillis=2024-06-07 16:47:17.426}] will not be managed by Spring
==>  Preparing: INSERT INTO sys_api (id,parent_id,operation,url,summary,method,status,create_time,update_time) VALUES (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?) , (?,?,?,?,?,?,?,?,?)
==>

SQL拦截:

INSERT INTO sys_api (id,parent_id,operation,url,summary,method,status,create_time,update_time) VALUES xxxxxx

数据库数据:
MyBatisPlus批量插入主键被覆盖问题解决插图(1)

总结

在有需要用到数据批量插入场景时,如果使用insertBatchSomeColumn进行数据插入,需要修改主键Id类型。特别是在使用到数据导入等功能使用到批量插入时,要注意Id被覆盖的问题。

本站无任何商业行为
个人在线分享 » MyBatisPlus批量插入主键被覆盖问题解决
E-->