跳到主要内容

批量操作

@BatchOperation、@BatchSize、@BatchData 注解使用指南

概述

批量操作用于一次性处理大量数据,比逐条操作更高效。MyBatisGX 内置批量操作方法,并支持自定义批量方法。

内置批量方法

CurdDao 内置方法

public interface CurdDao<ENTITY, ID> extends Dao {

// 批量插入
default int insertBatch(List<ENTITY> entityList) {
return this.insertBatch(entityList, 1000);
}

int insertBatch(@BatchData List<ENTITY> entityList, @BatchSize int batchSize);

// 批量删除
default int deleteBatchById(List<ID> ids) {
return this.deleteBatchById(ids, 1000);
}

int deleteBatchById(@BatchData List<ID> ids, @BatchSize int batchSize);

// 批量更新
default int updateBatchById(List<ENTITY> entityList) {
return this.updateBatchById(entityList, 1000);
}

int updateBatchById(@BatchData List<ENTITY> entityList, @BatchSize int batchSize);
}

使用内置批量方法

批量插入

List<User> users = Arrays.asList(
new User("张三", 25),
new User("李四", 30),
new User("王五", 28)
);

// 使用默认批次大小(1000)
userDao.insertBatch(users);

// 自定义批次大小
userDao.insertBatch(users, 500);

批量删除

List<Long> ids = Arrays.asList(1L, 2L, 3L, 4L, 5L);

// 使用默认批次大小
userDao.deleteBatchById(ids);

// 自定义批次大小
userDao.deleteBatchById(ids, 100);

批量更新

List<User> users = userDao.findList(query);
// 修改数据
users.forEach(u -> u.setStatus(1));

// 批量更新
userDao.updateBatchById(users);

自定义批量方法

注解说明

注解说明
@BatchOperation标记方法为批量操作
@BatchData标记参数为批量数据
@BatchSize标记参数为批次大小

自定义批量插入

@Repository
public interface UserDao extends SimpleDao<User, UserQuery, Long> {

@BatchOperation
int insertUsers(@BatchData List<User> users, @BatchSize int batchSize);
}

// 使用
userDao.insertUsers(users, 500);

自定义批量更新

@Repository
public interface UserDao extends SimpleDao<User, UserQuery, Long> {

@BatchOperation
int updateStatusBatch(@BatchData List<User> users, @BatchSize int batchSize);
}

// 使用
List<User> users = ...;
users.forEach(u -> u.setStatus(1));
userDao.updateStatusBatch(users, 100);

自定义批量删除

@Repository
public interface UserDao extends SimpleDao<User, UserQuery, Long> {

@BatchOperation
int deleteByNames(@BatchData List<String> names, @BatchSize int batchSize);
}

// 使用
List<String> names = Arrays.asList("张三", "李四", "王五");
userDao.deleteByNames(names, 100);

批次大小选择

批次大小适用场景
100-500数据量大、单条数据复杂
500-1000一般场景(默认 1000)
1000-5000数据量小、单条数据简单

性能考虑

┌─────────────────────────────────────────────────────────────────┐
│ 批次大小与性能 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 批次太小: │
│ - 大量 SQL 执行次数 │
│ - 网络往返开销大 │
│ │
│ 批次太大: │
│ - 单次 SQL 过长 │
│ - 内存占用高 │
│ - 可能触发数据库限制 │
│ │
│ 建议: │
│ - 根据数据复杂度调整 │
│ - 参考数据库 max_allowed_packet 配置 │
│ │
└─────────────────────────────────────────────────────────────────┘

完整示例

// 用户实体
@Entity
@Table(name = "user")
public class User {

@Id
private Long id;

private String name;

private Integer age;

private Integer status;
}

// DAO 接口
@Repository
public interface UserDao extends SimpleDao<User, UserQuery, Long> {

// 自定义批量方法
@BatchOperation
int insertUsers(@BatchData List<User> users, @BatchSize int batchSize);

@BatchOperation
int updateStatusBatch(@BatchData List<User> users, @BatchSize int batchSize);
}

// Service 使用
@Service
public class UserService {

@Autowired
private UserDao userDao;

public void importUsers(List<UserDTO> dtos) {
List<User> users = dtos.stream()
.map(dto -> {
User user = new User();
user.setName(dto.getName());
user.setAge(dto.getAge());
return user;
})
.collect(Collectors.toList());

// 批量插入,每 500 条一批
userDao.insertBatch(users, 500);
}

public void batchUpdateStatus(List<Long> ids, Integer status) {
List<User> users = ids.stream()
.map(id -> {
User user = new User();
user.setId(id);
user.setStatus(status);
return user;
})
.collect(Collectors.toList());

userDao.updateBatchById(users, 1000);
}
}

批量操作与其他功能配合

与字段值生成配合

批量操作时,字段值生成器会正常执行:

@Entity
@Table(name = "user")
public class User {

@Id
@GeneratedValue(IdValueProcessor.class)
private Long id;

@Column(name = "input_time")
@GeneratedValue(InputTimeValueProcessor.class)
private LocalDateTime inputTime;
}

// 批量插入时,id 和 inputTime 自动填充
userDao.insertBatch(users);

与乐观锁配合

批量更新时会检查版本号:

@Entity
@Table(name = "user")
public class User {

@Id
private Long id;

private String name;

@Version
private Integer version;
}

// 批量更新时会检查 version
userDao.updateBatchById(users);

与逻辑删除配合

批量删除时会执行逻辑删除:

@Entity
@Table(name = "user")
public class User {

@Id
private Long id;

@LogicDelete
private Integer status;
}

// 批量删除会执行 UPDATE SET status = 1
userDao.deleteBatchById(ids);

注意事项

  1. 内存考虑:大批量操作注意内存占用,建议分批处理

  2. 事务边界:批量操作应在事务内执行

  3. 失败处理:批量操作中某条失败可能影响整批,需要业务处理

  4. 数据库限制:注意数据库单次 SQL 大小限制

  5. 连接超时:大批量操作可能需要调整数据库连接超时配置

下一步