休眠多对多 - 获取方法渴望与懒惰 [英] Hibernate many to many - fetch method eager vs lazy

查看:37
本文介绍了休眠多对多 - 获取方法渴望与懒惰的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Hibernate 的新手.

New to Hibernate.

我有用户组的多对多关系.三个表: User 、 Group 和 UserGroup 映射表.

I have User Group many to many relation. Three tables : User , Group and UserGroup mapping table.

实体:

@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

请注意,在 Group Entity 中,我使用的是 EAGER 获取方法.现在,当我调用我的 DAO 来检索系统中的所有组时使用以下标准:

Notice that in Group Entity I'm using fetch method EAGER. Now, when I'm calling my DAO to retrive all the groups in the system using the following criteria:

  Criteria criteria = session.createCriteria(Group.class);
  return criteria.list();

我从 mappgin 表(用户组)中获取所有行,而不是获取实际的组数...

I'm getting all the rows from the mappgin table (usergroup) instead of getting the actual number of groups...

例如,如果我有在用户表中

for example if i have in user table

 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}

The result will be the following list - {grp1,grp2,grp2,grp1}

代替{grp1,grp2}

Instead of {grp1,grp2}

如果我在 Group Entity 中将 fetch 方法更改为 LAZY 我会得到正确的结果但是 hibernate 在另一个地方抛出了我的 LazyException ......

If I change in Group Entity the fetch method to LAZY I'm getting the correct results but hibernate throws me LazyException in another place...

请帮助我应该使用什么获取方法以及为什么?

Please assist what fetch method should I use and why ?

谢谢!

推荐答案

懒惰的人会告诉你总是违反直觉地使用 FetchType.EAGER.这些人通常不担心数据库性能,只关心让他们的开发生活更轻松.我会说你应该使用 FetchType.LAZY 来提高性能.因为数据库访问通常是大多数应用程序的性能瓶颈,所以一点点帮助.

Lazy people will tell you to always use FetchType.EAGER counter-intuitively. These are the people who generally don't worry about database performance and only care about making their development lives easier. I'm going to say you should be using FetchType.LAZY for the increased performance benefit. Because database access is usually the performance bottleneck of most applications, every little bit helps.

如果您确实需要获取某个组的用户列表,只要您在事务会话中调用 getUsers(),您就不会收到 LazyLoadingException 这是所有新 Hibernate 用户的祸根.

If you do actually need to get a list of users for a group, as long as your call getUsers() from within a transactional session, you won't get that LazyLoadingException that is the bane of all new Hibernate users.

以下代码将为您提供所有组,而无需填充这些组的用户列表

The following code will get you all groups without populating the list of users for those groups

//Service Class
@Transactional
public List<Group> findAll(){
    return groupDao.findAll();
}

以下代码将为您提供所有组以及这些组在 DAO 级别的用户:

The following code will get you all groups with the users for those groups at the DAO level:

//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 的更多信息,请参见此处

For more info on the different types of FetchMode's see here

如果您不想为了访问集合对象而编写不同的 DAO 方法,只要您在用于获取父对象的同一个 Session 中,您就可以使用 Hibernate.initialize() 方法来强制初始化您的子集合对象.我真的不建议您对父对象的 List 执行此操作.这会给数据库带来相当大的负载.

If you don't want to have to write a different DAO method just to access your collection object, as long as you are in the same Session that was used to fetch the parent object you can use the Hibernate.initialize() method to force the initialisation of your child collection object. I would seriously not recommend that you do this for a List<T> of parent objects. That would put quite a heavy load on the database.

//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() 的更多信息,请参见 这里

I've not come across a situation where I've had to use the above code, but it should be relatively efficient. For more information about Hibernate.initialize() see here

我在服务层完成了这个,而不是在 DAO 中获取它们,因为那样你只需要在服务中创建一个新方法而不是创建一个单独的 DAO 方法.重要的是您已经在事务中封装了 getUsers() 调用,因此将创建一个会话,Hibernate 可以使用该会话来运行其他查询.这也可以在 DAO 中通过为您的集合编写连接标准来完成,但我自己从来没有这样做过.

I have done this in the service layer rather than fetching them in the DAO, because then you only have to create one new method in the service rather than making a separate DAO method as well. The important thing is that you have wrapped the getUsers() call within the transaction, so a session will have been created that Hibernate can use to run the additional queries. This could also be done in the DAO by writing join criteria to your collection, but I've never had to do that myself.

也就是说,如果您发现调用第二种方法的次数远远多于调用第一种方法,请考虑将提取类型更改为 EAGER 并让数据库为您完成工作.

That said, if you find that you are calling the second method far more than you are calling the first, consider changing your fetch type to EAGER and letting the database do the work for you.

这篇关于休眠多对多 - 获取方法渴望与懒惰的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆