TK Mapper批量插入-自定义ID

2026-05-15

tk mapper version: 4.2.1

java version: 8

springboot version: 2.3.1.RELEASE

背景

项目本身实现了批量插入接口,但是由于没有业务需要这个功能,所以一直没有使用过,直到有个需求是支持多条会员余额变化记录。原来的逻辑是一个请求过来后会员余额只有一次增加或减少,所以对应的记录只有一条,现在要改成一个请求支持多次增加/减少。

问题

如果直接调用insertList方法,则会报错id为null。

@Repository
public interface CustomMapper<T> extends Mapper<T>, MySqlMapper<T>, IdsMapper<T> {

}

// 其中MysqlMapper中则继承了批量插入接口, 也就是InsertListMapper
@RegisterMapper
public interface MySqlMapper<T> extends InsertListMapper<T>, InsertUseGeneratedKeysMapper<T> {
}

解决

目前id是通过执行一条sql来生成的,当执行insert前会先执行一次select id,批量插入时只执行一次select,明显是不行的。

@Data
public abstract class BaseEntity implements Serializable {

    private static final long serialVersionUID = 35L;

    @Id
    @GeneratedValue(generator = "select id_generator()")
    private Long id;
}

那么,是不是可以在执行insert前手动setId,这样所有数据都有id了。

然而发现还是不行...

经过查阅文档,发现有两个批量插入的接口

tk.mybatis.mapper.common.special.InsertListMapper

不支持主键自动生成

tk.mybatis.mapper.additional.insert.InsertListMapper

支持主键自动生成

然而项目中继承的MysqlMapper使用的是不支持主键生成的,所以就算手动设置了还是会变成null。

实现

使用支持主键自动生成的InsertListMapper, 然后添加一个生成idList的方法。

import tk.mybatis.mapper.additional.insert.InsertListMapper;

@Repository
public interface CustomMapper<T> extends Mapper<T>, InsertListMapper<T>, InsertUseGeneratedKeysMapper<T>, IdsMapper<T> {

    /**
     * Generate multiple IDs using PostgreSQL id_generator() function
     * @param count number of IDs to generate
     * @return list of generated IDs
     */
    List<Long> generateIds(@Param("count") int count);
}

在执行批量插入前获取idList,手动设置Entity ID。

public int save(List<T> models) {
        // Pre-generate IDs for all models before batch insert
        List<Long> ids = customMapper.generateIds(models.size());
        for (int i = 0; i < models.size(); i++) {
            T model = models.get(i);
            setMerchantId(model);
            if (model.getId() == null && i < ids.size()) {
                model.setId(ids.get(i));
            }
        }
        return customMapper.insertList(models);
    }

优化

由于本次改动需要支持的业务是余额变动记录,一般不会产生大于10条记录,所以InsertList可以不用分批次,直接插入完所有,但是如果后面其他需求是要批量插入大量数据的话,还是要进行分批次插入,比如每次一千条。