显式EntityManager.find之后@RequestScoped Bean中的LazyInitializationException

时间:2011-06-06 14:15:24

标签: java hibernate jboss lazy-loading jboss6.x

我们目前正在从JavaEE5迁移到JavaEE6,并且正在使用JBoss 6.0.0和JSF2。为简单起见,此示例是基于Maven原型构建的:org.jboss.weld.archetypes:jboss-javaee6-webapp:1.0.1.CR2

我在User添加了一个简单的LAZY关系:

@NotNull @ManyToMany(fetch=FetchType.LAZY)
private List<Address> addresses;

这个bean是maven原型的一部分,我向retrieveAllMembersOrderedByName()添加了几行。

@RequestScoped
public class MemberListProducer {
    @Inject private Logger log;

    @Inject @MemberRepository
    private EntityManager em;

    private List<Member> members;

    @Produces  @Named
    public List<Member> getMembers(){return members;}

    @PostConstruct
    public void retrieveAllMembersOrderedByName()
    {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Member> criteria = cb.createQuery(Member.class);
        Root<Member> member = criteria.from(Member.class);
        criteria.select(member).orderBy(cb.asc(member.get("name")));
        members = em.createQuery(criteria).getResultList();

        Member m1 = members.get(0);
        log.info("Id: "+m1.getId());

        Member m2 = em.find(Member.class, m1.getId());

        log.info("Addr m1: "+m1.getAddresses().size());  // OK
        log.info("Addr m2: "+m2.getAddresses().size());  // Error
    }}

如您所见,CriteriaQuery检索到List<Member>,然后从列表中取出Member m1,并从同一Member m2显式加载EntityManager em。现在有趣的部分:m1.getAddresses().size()有效,m2.getAddresses().size()给出了

    15:41:32,910 ERROR [org.hibernate.LazyInitializationException]
failed to lazily initialize a collection of role: test.Member.addresses,
no session or session was closed: org.hibernate.LazyInitializationException:
failed to lazily initialize a collection of role:test.Member.addresses,
no session or session was closed

任何人都可以解释一下,或者知道如何解决这个问题?谢谢,托尔

3 个答案:

答案 0 :(得分:0)

这是延迟加载的所有惰性类都是代理的正常行为。当你从代理中提取类时,你的Hibernate会话已经关闭。

解决方案是在View Filter中实现Open Session,这将使您的Hibernate会话保持打开状态,直到您的Request处于活动状态。

您可以在本文中阅读更多相关信息

http://community.jboss.org/wiki/OpenSessionInView

如果您使用的是Spring Framework,那么您已经完成了OpenSessionInViewFilter课程。

希望它有所帮助。

答案 1 :(得分:0)

托尔,请你仔细检查一下?我认为这很有趣并且自己尝试过,但是我在两次调用中都得到了例外。它们都不起作用。我可能做错了但我已经检查了几次,这两种方法都给了我这个例外。您是否让记录器记录第一个集合的大小?

答案 2 :(得分:0)

您可以通过下面给出的具有默认延迟初始化的代码动态获取相关对象:

criteria.setFetchMode(“addresses”,FetchMode.JOIN);