从EJB抛出的LazyInitializationException

时间:2012-11-10 23:16:28

标签: java java-ee

我创建了一个公开为Web服务(REST)的EJB。但是,当我尝试它时,我得到以下例外。我将其追溯到我在问题实体上的JPA注释。当我取消注释@ManyToOne映射(具有fetch属性的映射)时,它似乎抛出此异常。我故意将实体可能与其他实体建立的所有关系都FetchType.LAZY。我想保持这种方式。

我正在使用容器管理的事务和所有正常的EJB荣耀。为什么会这样?有什么修复?

修改 我有一个用@Stateless注释的存储库类,然后我在另一个EJB中使用这个类,它从存储库中检索一个问题列表。最后我有一个资源,也注明了@Stateless。是因为某些持久性上下文还是什么?

PS我已经从实体中遗漏了所有其他内容,当我按照描述修复注释时,代码可以正常工作。

@Entity
public class Question extends AbstractModel {

    private int id;
    private Participant participant;
    private List<Answer> answers;
    private List<QuestionCategory> categories;
    private List<QuestionFeedback> feedback;

    public Question() {
        answers = new ArrayList<Answer>();
        categories = new ArrayList<QuestionCategory>();
        feedback = new ArrayList<QuestionFeedback>();
    }

    @ManyToOne
    //@ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ParticipantId")
    public Participant getParticipant() {
        return participant;
    }

    //@OneToMany(cascade = CascadeType.ALL)
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "QuestionId", nullable = false)
    public List<Answer> getAnswers() {
        return answers;
    }

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "QuestionQuestionCategory",
            joinColumns = @JoinColumn(name = "QuestionId", nullable = false),
            inverseJoinColumns = @JoinColumn(name = "QuestionCategoryId", nullable = false)
    )
    public List<QuestionCategory> getCategories() {
        return categories;
    }

    //@OneToMany(cascade = CascadeType.ALL)
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "QuestionId", nullable = false)
    public List<QuestionFeedback> getFeedback() {
        return feedback;
    }
}

引发此异常:

  

[#| 2012-11-11T00:10:59.182 + 0100 |警告| glassfish3.1.2 | javax.enterprise.system.container.web.com.sun.enterprise.web | _ThreadID = 71; _ThreadName = Thread- 8; | StandardWrapperValve [javax.ws.rs.core.Application]:   PWC1406:servlet javax.ws.rs.core.Application的Servlet.service()   抛出异常org.hibernate.LazyInitializationException:不能   初始化代理 - 没有会话   org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165)     在   org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:272)     在   org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)     at sun.reflect.GeneratedMethodAccessor76.invoke(Unknown Source)at   sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     在java.lang.reflect.Method.invoke(Method.java:601)at   com.sun.xml.bind.v2.runtime.reflect.Accessor $ GetterSetterReflection.get(Accessor.java:354)     在   com.sun.xml.bind.v2.runtime.reflect.Accessor.getUnadapted(Accessor.java:147)     在   com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor $ CompositeTransducedAccessorImpl.hasValue(TransducedAccessor.java:251)     在   com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty.serializeBody(SingleElementLeafProperty.java:105)     在   com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:358)     在   com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:350)     在   com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:696)     在   com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:158)     在   com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:358)     在   com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:696)     在   com.sun.xml.bind.v2.runtime.property.ArrayElementNodeProperty.serializeItem(ArrayElementNodeProperty.java:69)     在   com.sun.xml.bind.v2.runtime.property.ArrayElementProperty.serializeListBody(ArrayElementProperty.java:172)     在   com.sun.xml.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:159)     在   com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:358)     在   com.sun.xml.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:593)     在   com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:340)     在   com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:494)     在   com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:323)     在   com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:178)     在   com.sun.jersey.json.impl.BaseJSONMarshaller.marshallToJSON(BaseJSONMarshaller.java:103)     在   com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider.writeTo(JSONRootElementProvider.java:143)     在   com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:157)     在   com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306)     在   com.sun.jersey.server.impl.application.WebApplicationImpl 的handleRequest(WebApplicationImpl.java:1437)     在   com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)     在   com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)     在   com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)     在   com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)     在   com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)     在javax.servlet.http.HttpServlet.service(HttpServlet.java:770)at   org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)     在   org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)     在   org.apache.catalina.core.StandardContextValve。 _invoke(StandardContextValve.java:175)     在   org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java)     在   org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)     在   org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)     在   org.apache.catalina.core.StandardHostValve .__调用(StandardHostValve.java:161)     在   org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java)     在   org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)     在   org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)     在   com.sun.enterprise.v3.services.impl.ContainerMapper $ AdapterCallable.call(ContainerMapper.java:317)     在   com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)     在   com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)     在   com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)     在   com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)     在   com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)     在   com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)     在   com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)     在   com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)     在   com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)     在   com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)     在   com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)     在com.sun.grizzly.ContextTask.run(ContextTask.java:71)at   com.sun.grizzly.util.AbstractThreadPool $ Worker.doWork(AbstractThreadPool.java:532)     在   com.sun.grizzly.util.AbstractThreadPool $ Worker.run(AbstractThreadPool.java:513)     在java.lang.Thread.run(Thread.java:722)|#]

2 个答案:

答案 0 :(得分:2)

我遇到了Andy的确切问题。我到现在发现的是:

@ManyToOne
//@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ParticipantId")
public Participant getParticipant() {
    return participant;
}

可以LAZY设置为单个属性关联,但您不应该这样做。将@ManyToOne注释保留在那里:

  

延迟属性获取:属性或单值关联   访问实例变量时获取。 这种方法需要   构建时间字节码检测并且很少需要。

至于Collections,我已添加Hibernate.initialize(categories),如下所示:

  

有时需要在关闭之前初始化代理或集合   会话。您可以通过调用cat.getSex()或强制初始化   例如,cat.getKittens()。size()。但是,这可能令人困惑   对于代码的读者而言,通用代码并不方便。该   静态方法Hibernate.initialize()和Hibernate.isInitialized(),   为应用程序提供便捷的懒惰工作方式   初始化的集合或代理。 Hibernate.initialize(cat)会   强制执行代理cat的初始化,与其Session一样长   仍然打开。 Hibernate.initialize(cat.getKittens())有一个类似的   收集小猫的效果。

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "QuestionQuestionCategory",
        joinColumns = @JoinColumn(name = "QuestionId", nullable = false),
        inverseJoinColumns = @JoinColumn(name = "QuestionCategoryId", nullable = false)
)
public List<QuestionCategory> getCategories() {
    Hibernate.initialize(categories)
    return categories;
}

现在我有一个org.hibernate.HibernateException: collection is not associated with any session例外。根据粗体文本,会议应该是公开的。我仍然找不到在容器管理的应用程序中启动会话的方法。只是调用getCategories()不会做代理和会话初始化的技巧。

任何提示?

编辑:解决方案

可能您希望在用户单击某个内容时加载关联的集合,然后触发action或actionListener。

你要做的是(而且,这是非常通用的):

  • 使用find(Object id)方法实施Hibernate.initialize()方法(从上面代码段中的getCategories()方法中删除):

    public Question find(Object id) {
        Question question = getEntityManager().find(Question.class, id);
        Hibernate.initialize(question.getCategories());
        Hibernate.initialize(question.getAnswers());
        Hibernate.initialize(question.getFeedback());
    
        return question ;
    }
    
  • 视图请求加载时搜索实体:

    public void userHasClickedAQuestion(Object id) {
        selectedQuestion = questionFacade.find(id);
    }
    

你完成了。当您调用getter方法时,将加载并显示您的答案,问题和反馈。

答案 1 :(得分:0)

LazyInitializationException:在Session(否则:EntityManager)关闭后,其实体将分离。问题是,对象(QuestionFeedbackQuestionCategoryAnswer)的集合是分离的。如果您在lazy=false中使用FetchType.EAGER(否则:hibernate),即使Session已关闭,对象集合也会加载到内存中。

参考:Hibernate: Understanding Lazy Fetching