如何在Hibernate中批量处理@ManyToMany关联的查询与插入?
Hibernate多对多关联的批量查询与批量插入优化
我定义了User和Role两个实体类,二者为单向@ManyToMany关联,实体代码如下:
User实体类
@Entity @Table(name = "users") @Getter @Setter public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String firstName; private String lastName; private String email; private String password; @ManyToMany @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id")) private Set<Role> roles = new HashSet<>(); }
Role实体类
@Entity @Table(name = "roles") @Getter @Setter public class Role { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String name; }
在执行更新用户角色的测试方法时:
@Test @Transactional void updateUser(){ User user = userRepository.findById(1L).get(); List<Integer> roleIds = new LinkedList<>(); roleIds.add(5); roleIds.add(6); roleIds.add(7); roleIds.add(8); roleIds.add(9); roleIds.add(10); roleIds.add(11); roleIds.add(12); roleIds.add(13); roleIds.add(14); roleIds.add(15); for(int roleId : roleIds){ Role role1 = new Role(); role1.setId(roleId); user.getRoles().add(role1); } userRepository.saveAndFlush(user); }
调用saveAndFlush(user)后,Hibernate会针对每个roleId执行单独的SELECT语句验证角色存在,同时对关联表users_roles执行多条单独的INSERT语句。由于业务限制无法通过重写isNew方法规避查询,请问如何实现批量查询(用IN语句)和批量插入?
解决方案
1. 实现批量查询Role
当前代码手动创建Role对象并设置ID,Hibernate会将这些对象视为瞬态对象,为了确保关联的是数据库中存在的持久化对象,会逐个执行SELECT查询验证。
优化方式:通过JPA Repository的批量查询方法一次性获取所有目标Role,替代逐个创建对象的逻辑:
步骤1:在RoleRepository中添加批量查询方法
public interface RoleRepository extends JpaRepository<Role, Long> { List<Role> findByIdIn(List<Long> roleIds); }
步骤2:修改测试方法中的角色添加逻辑
@Test @Transactional void updateUser(){ User user = userRepository.findById(1L).get(); List<Long> roleIds = Arrays.asList(5L,6L,7L,8L,9L,10L,11L,12L,13L,14L,15L); // 批量查询所有目标Role,仅执行一条带IN的SELECT语句 List<Role> targetRoles = roleRepository.findByIdIn(roleIds); user.getRoles().addAll(targetRoles); userRepository.saveAndFlush(user); }
这样Hibernate只会执行一条SELECT * FROM roles WHERE id IN (5,6,...15)的语句,避免了多次单条查询。
2. 实现关联表的批量插入
默认情况下Hibernate会逐个插入关联表记录,需要通过配置开启JDBC批量操作:
在application.properties(或application.yml)中添加以下配置:
# 开启批量操作,设置批量大小 spring.jpa.properties.hibernate.jdbc.batch_size=20 # 对INSERT语句排序,确保同表的INSERT能被批量处理 spring.jpa.properties.hibernate.order_inserts=true # 对UPDATE语句排序(可选,按需开启) spring.jpa.properties.hibernate.order_updates=true # 批量处理带版本控制的数据(如果实体用了@Version乐观锁则开启) spring.jpa.properties.hibernate.batch_versioned_data=true
配置后,Hibernate会将多条INSERT INTO users_roles(user_id, role_id) VALUES (?,?)合并成批量语句执行,减少数据库交互次数。
内容的提问来源于stack exchange,提问作者Anand Kadhi
相关产品推荐
相关产品推荐

