Java 当添加到@ManyToMany的拥有方集合时,最好避免选择所有行
当添加到表示@ManyToMany关联的拥有方的集合时,我的JPA实现(Hibernate)将首先从该关联中选择所有行,以确定该实体是否已存在于集合中 我理解这背后的机制,但在处理大型联接表时,这不是很有效。当我知道需要插入一个条目时,避免加载联接表的所有元素的最佳做法是什么 我将以一个经典的用户/角色场景为例,为简洁起见,省略了getter/setter/initializer:Java 当添加到@ManyToMany的拥有方集合时,最好避免选择所有行,java,sql,hibernate,jpa,many-to-many,Java,Sql,Hibernate,Jpa,Many To Many,当添加到表示@ManyToMany关联的拥有方的集合时,我的JPA实现(Hibernate)将首先从该关联中选择所有行,以确定该实体是否已存在于集合中 我理解这背后的机制,但在处理大型联接表时,这不是很有效。当我知道需要插入一个条目时,避免加载联接表的所有元素的最佳做法是什么 我将以一个经典的用户/角色场景为例,为简洁起见,省略了getter/setter/initializer: @Entity public class User { @Id private Long id;
@Entity
public class User {
@Id
private Long id;
@ManyToMany
private Set<Role> roles;
}
@Entity
public class Role {
@Id
private Long id;
private String name;
@ManyToMany(mappedBy = "roles")
private Set<User> users;
}
当我添加到user.roles时,将执行以下选择:
select
roles0_.users_id as users_id1_20_0_,
roles0_.roles_id as roles_id2_21_0_,
role1_.id as id1_17_1_,
role1_.name as name2_17_1_
from User_Role roles0_
inner join Role role1_ on roles0_.roles_id=role1_.id
where roles0_.users_id=?
这对于小的集合是好的,但是对于大的集合是有问题的
我可以想到以下解决方案,我想知道我应该选择哪一种,或者是否有更好的方法
1.执行本机查询:
2.为联接表创建实体:
然后我可以运行:
User user = em.find(User.class, 1L);
Role role = em.find(Role.class, 1L);
UserRole userRole = new UserRole(user, role);
em.persist(userRole);
我倾向于使用本机查询来进行插入,但我很想得到一些反馈,了解最“JPA”的方法是什么。java持久化与hibernate的书(第298页)说,多对多通常最好使用关联类(有点像第二个解决方案中已经使用的,使用UserRole)然后映射任意一方的两个一对多关系——即每个用户有多个userrole,每个角色有多个userrole。这是最“JPA”的做事方式,我认为会得到你想要的性能 现在让我们来看看其中的微妙之处:
Hibernate还支持bag选项,该选项允许重复,因此可能会避免检查…但是,您的数据库中会有重复的关系。您的两种解决方案至少有一个缺点。只需在二级缓存或当前持久性上下文中查看它。您必须非常小心,不要出错我将跟踪这篇文章,这是一个非常有趣的问题。谢谢@zxcf-我没有考虑持久性上下文/二级缓存,但显然这需要解决。考虑到这一点,绝对需要一个更好的解决方案来避免错误和不必要的管道,如缓存逐出等。谢谢@DavidInTx-当我第一次访问时读了你的帖子,我觉得“就是这样!”,但后来我开始思考——我需要执行role.getUserRoles().remove(userRole)等操作,这难道不会导致Hibernate加载所有关联,就像我最初的困境一样吗?
INSERT INTO User_Role (users_id, roles_id) VALUES (1, 1)
@Entity
IdClass(UserRole.PK)
public class UserRole {
@Id
private User user;
@Id
private Role role;
public static class PK {
private User user;
private Role role;
}
}
User user = em.find(User.class, 1L);
Role role = em.find(Role.class, 1L);
UserRole userRole = new UserRole(user, role);
em.persist(userRole);