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来提高性能。由于数据库访问通常是大多数应用程序的性能瓶颈,因此一点点帮助。
FetchType.EAGER
FetchType.LAZY
如果确实需要获取组的用户列表,只要您getUsers()在事务会话中进行呼叫,就不会得到LazyLoadingException所有新Hibernate用户的麻烦。
getUsers()
LazyLoadingException
以下代码将为您提供所有组,而无需填充这些组的用户列表
//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的更多信息,请参见此处
FetchMode
如果您不想只为访问集合对象而编写其他DAO方法,只要您与Session用于获取父对象的对象相同,则可以使用该Hibernate.initialize()方法来强制初始化子集合宾语。我不建议您List<T>对父对象执行此操作。这将对数据库造成相当大的负担。
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()请参见此处
我已经在服务层中完成了此操作,而不是在DAO中获取它们,因为那样的话,您只需要在服务中创建一个新方法,而不必再创建单独的DAO方法。重要的是您已将getUsers()调用包装在事务中,因此将创建一个会话,Hibernate可以使用该会话来运行其他查询。也可以在DAO中通过向您的集合编写联接条件来完成此操作,但是我从来不必自己做。
就是说,如果您发现调用第二个方法的次数比调用第一个方法的次数多,请考虑将获取类型更改为EAGER并让数据库为您完成工作。
EAGER