Hibernate 新手。
我有用户组多对多关系。 三张表:User、Group 和 UserGroup 映射表。
实体:
@Entity
@Table(name = "user")
public class User {
@Id
@Column (name = "username")
private String userName;
@Column (name = "password", nullable = false)
private String password;
@ManyToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
@JoinTable(name="usergroup",
joinColumns={@JoinColumn(name="username")},
inverseJoinColumns={@JoinColumn(name="groupname")})
private Set<Group> userGroups = new HashSet<Group>();
... setter and getters
@Entity
@Table(name = "group")
public class Group {
@Id
@Column(name = "groupname")
private String groupName;
@Column(name = "admin", nullable = false)
private String admin;
@ManyToMany(mappedBy = "userGroups", fetch = FetchType.EAGER)
private Set<User> users = new HashSet<User>();
... setter and getters
请注意,在组实体中,我使用的是获取方法 EAGER。 现在,当我调用我的 DAO 来检索系统中的所有组时 使用以下标准:
Criteria criteria = session.createCriteria(Group.class);
return criteria.list();
我从 mappgin 表(用户组)中获取所有行,而不是获取组的实际数量...
例如如果我有 在用户表中
username password
-----------------
user1 user1
user2 user2
在组表中
groupname admin
---------------
grp1 user1
grp2 user2
在用户组表中
username groupname
------------------
user1 grp1
user2 grp2
user1 grp2
user2 grp1
结果将是以下列表 - {grp1,grp2,grp2,grp1}
代替{grp1,grp2}
如果我将组实体中的获取方法更改为 LAZY,我将得到正确的结果 但是 hibernate 在另一个地方抛出 LazyException ...
请协助我应该使用什么获取方法以及为什么?
谢谢!
最佳答案
懒人会告诉你总是使用FetchType.EAGER
违反直觉。这些人通常不担心数据库性能,只关心让他们的开发生活更轻松。我会说你应该使用 FetchType.LAZY
以获得更高的性能优势。因为数据库访问通常是大多数应用程序的性能瓶颈,所以一点一滴都有帮助。
如果您确实需要获取某个组的用户列表,只要您调用 getUsers()
在交易 session 中,您不会得到 LazyLoadingException
这是所有 Hibernate 新用户的祸根。
以下代码将为您获取所有组,而无需填充这些组的用户列表
//Service Class
@Transactional
public List<Group> findAll(){
return groupDao.findAll();
}
以下代码将在 DAO 级别为您提供所有组以及这些组的用户:
//DAO class
@SuppressWarnings("unchecked")
public List<Group> findAllWithUsers(){
Criteria criteria = getCurrentSession().createCriteria(Group.class);
criteria.setFetchMode("users", FetchMode.SUBSELECT);
//Other restrictions here as required.
return criteria.list();
}
编辑 1:感谢 Adrian Shum 提供此代码
有关不同类型的更多信息 FetchMode
看here
如果您不想为了访问您的集合对象而编写不同的 DAO 方法,只要您在同一个 Session
中即可。用于获取父对象的,您可以使用 Hibernate.initialize()
强制初始化子集合对象的方法。我严重不建议您为 List<T>
这样做的父对象。这会给数据库带来相当大的负载。
//Service Class
@Transactional
public Group findWithUsers(UUID groupId){
Group group = groupDao.find(groupId);
//Forces the initialization of the collection object returned by getUsers()
Hibernate.initialize(group.getUsers());
return group;
}
我没有遇到过必须使用上面代码的情况,但它应该是相对高效的。有关 Hibernate.initialize()
的更多信息见here
我在服务层完成了这个,而不是在 DAO 中获取它们,因为那样你只需要在服务中创建一个新方法,而不是同时创建一个单独的 DAO 方法。重要的是你已经包装了 getUsers()
在事务中调用,因此将创建一个 session ,Hibernate 可以使用该 session 来运行其他查询。这也可以在 DAO 中通过将连接条件写入您的集合来完成,但我自己从来没有这样做过。
也就是说,如果您发现调用第二种方法的次数远远超过调用第一种方法的次数,请考虑将获取类型更改为 EAGER
。让数据库为您完成工作。
关于java - hibernate 多对多-获取方法渴望与懒惰,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24150199/