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

背景

通过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

数据库数据:

在这里插入图片描述

  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

数据库数据:
在这里插入图片描述

总结

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

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MybatisPlus是一个基于Mybatis的增强工具库,在Mybatis的基础上加入了许多实用的增强功能,其中就包括批量插入。 通过MybatisPlus实现批量插入,可以通过以下步骤实现: 1. 创建一个List对象,用于存储要批量插入的数据。 2. 在实体类中使用注解@TableId(value = "id", type = IdType.AUTO)来指定主键生成策略。 3. 在Mapper接口中定义一个批量插入的方法,方法参数类型为List,使用注解@Param来指定参数名称。 4. 在Mapper映射文件中,使用foreach标签遍历List集合中的数据,将数据插入到数据库中。 举例来说,假设我们要批量插入学生信息,代码实现如下: 1. 创建一个List对象: List<Student> list = new ArrayList<>(); 2. 在实体类中使用注解@TableId指定主键生成策略: @TableId(value = "id", type = IdType.AUTO) public class Student { private Long id; ... } 3. 在Mapper接口中定义批量插入的方法: void insertBatch(@Param("list") List<Student> list); 4. 在Mapper映射文件中,使用foreach标签遍历List集合中的数据: <insert id="insertBatch" parameterType="java.util.List"> insert into student(id, name, age, gender) values <foreach collection="list" item="item" separator=","> (#{item.id}, #{item.name}, #{item.age},#{item.gender}) </foreach> </insert> 通过以上步骤,就可以轻松地实现MybatisPlus批量插入。值得注意的是,在使用批量插入时,需要考虑数据库中的主键是否重复,需要根据具体情况选择不同的主键生成策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值