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了。
然而发现还是不行...
经过查阅文档,发现有两个批量插入的接口
然而项目中继承的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可以不用分批次,直接插入完所有,但是如果后面其他需求是要批量插入大量数据的话,还是要进行分批次插入,比如每次一千条。