以最简单的方式使用一对多的LazyInitializationException

时间:2011-09-27 10:06:44

标签: java hibernate spring jpa

我正在使用Hibernate和jpa,我正在尝试使用LazyInizializationException做一个非常简单的事情。我知道LazyInizializationException意味着什么,但我无法理解为什么它以最常见和最简单的方式做所有事情。这是这段关系的“一面”:

@Entity
public class User implements Serializable{

@Id @GeneratedValue
private int idUser;

private String name;
private String surname;
private String username;

@OneToMany(mappedBy="user")
private List<Device> dev;

...getters and setters...

这就是“很多”方面:

@Entity
public class Device implements Serializable {

@Id @GeneratedValue
private int idDevice;

private String brand;
private String model;

@ManyToOne
@JoinColumn(name="user_fk")
private User user;

...getters and setters...

抛出异常的jUnit测试是:

@Test
public void testLazyUserSnd() {
    User u = uDao.getUser(2);
    List<Device> devList = u.getDev();
    Device aDevice = devList.get(0); // <--- Here the exception is thrown
    aDevice.getModel();

我按照Hibernate Documentation中的解释建立了这种关系。任何提示?我犯了一些大而愚蠢的错误吗?

3 个答案:

答案 0 :(得分:3)

虽然@ Xavi的答案非常合理,但您可能并不总是想为用户加载设备。如果不这样做,有两种方法可以解决这个问题。

  1. 创建一个额外的方法uDao.getUserWithDevices(id)并在您知道需要设备时调用它,否则调用uDao.getUser(id)。
  2. 在事务中封装测试方法,以及使用该方法的任何生产代码。换句话说,只要你需要,就保持会话开放。
  3. 我个人使用事务方法,因为它允许更多的灵活性,并允许JPA在需要时延迟加载。有关会话生命周期的更多有趣信息,另请参阅http://community.jboss.org/wiki/OpenSessionInView

答案 1 :(得分:1)

异常告诉您,当会话关闭时,您正试图获取一些延迟加载的关联元素。当hibernate会话仍处于打开状态时,你应该在dao的方法中调用u.getDev()Hibernate.initialize(u.getDev())

或者,如果您使用的是Criteria,则还可以使用setFetchMode来强制提取。

 public User getUser(String id) {
   Session session = getSession();
   Criteria criteriaQuery = session.createCriteria(User.class);
   criteriaQuery.add(Expression.eq("id", id));
   criteriaQuery.setFetchMode("dev", FetchMode.JOIN);
   return criteriaQuery.uniqueResult();
 }

答案 2 :(得分:0)

当您访问关系时,实体可能与会话(事务上下文)分离。尝试将您的测试方法包含在事务中。