Hibernate在不同的事务中初始化对象

时间:2013-02-06 08:37:19

标签: spring hibernate jpa jpa-2.0 spring-transactions

我得到了着名的LazyInitializationException。

我有一个存储在会话中的对象User。该对象包含一个其他对象Market,它是惰性初始化的。 当我在会话中加载用户时,我不会加载Market因为它太重而且我不是每次都需要它。

当我想加载市场时,我处于不同的交易中,我不想从数据库重新加载用户。如何检索Market对象?知道User.market包含Hibernate代理,因此市场的ID和我不想用反射来破解Hibernate。

如果我可以加载市场而不将其加载到用户中,那将会更好。由于用户在会话中,我不想在会话中放入大量内容。

JPA兼容的解决方案会更好。

干杯

5 个答案:

答案 0 :(得分:2)

如果热门模式提取不可接受,并且如果交易无法维持到市场检索,则可以实施特定的dao方法以从用户专门检索市场

public List<Market> retrieveMarketFromUser (final User user) {
  Query query = session.createQuery("SELECT m FROM User AS u INNER JOIN u.market as m WHERE u.userid = :uid");
  query.setParameter("uid", user.getId());
  List<Market> list = query.list();
  return list;
}

或简短版

  Query query = session.createQuery("SELECT u.market FROM User AS u WHERE u.userid = :uid");

这可能不是您期望的JPA解决方案,只是一种解决方法。

答案 1 :(得分:1)

如果关系是双向的,那么您可以使用where market.user.id = ?之类的子句独立加载市场。

答案 2 :(得分:1)

为什么明显的解决方案不好?与建议的ring0一样,或者如果您已在findById对象中拥有ID,则只需使用findUser方法。

//if using a session factory
session.findById(Market.class, marketId); 

//if using the EntityManager
em.find(Market.class, marketId);

根据current_session_context_class配置的方式(我在hibernate.cfg.xml中拥有它),您可能会在每个新事务中都有一个新会话。如果是这种情况,你不必担心在那里放太多东西。您可以在上下文会话中找到更多信息here

答案 3 :(得分:1)

您需要做的是注释访问者而不是字段。这将允许您在最初加载用户时避免加载市场对象,但您可以从Hibernate代理对象访问市场ID,而不会触发延迟加载或获取LazyInitializationException。然后,当您想要加载市场本身时,您可以根据其ID进行正常的实体检索。您可以阅读有关其工作原理的详细说明here

答案 4 :(得分:-1)

既然你已经提到了新的事务,那么你可能会使用属于线程的新的hibernate会话,

使用这种与hibernate会话的直接交互

   obj = session.merge(obj);

如果您使用JPA2 Api

   obj=   entityManager.merge(obj);

如果有帮助,请评价答案。 干杯