使用EntityManager和Glassfish v3的异常-IllegalStateException:尝试在关闭的EntityManager上执行操作

时间:2018-11-08 18:34:08

标签: java java-ee ejb glassfish-3 entitymanager

我在使用JavaEE的项目中工作。我使用Glassfish服务器版本3。我在使用EntityManager实例的单例EJB中经常遇到问题(并非总是如此)。很多时候,我得到这个错误:

[timestamp] [http-thread-pool-8080(49)] ERROR com.sun.xml.ws.server.sei.TieHandler.serializeResponse Attempting to execute an operation on a closed EntityManager.
java.lang.IllegalStateException: Attempting to execute an operation on a closed EntityManager.
 at org.eclipse.persistence.internal.jpa.EntityManagerImpl.verifyOpen(EntityManagerImpl.java:1662) ~[org.eclipse.persistence.jpa.jar:2.3.4.v20130626-0ab9c4c]
 at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:643) ~[org.eclipse.persistence.jpa.jar:2.3.4.v20130626-0ab9c4c]
 at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:532) ~[org.eclipse.persistence.jpa.jar:2.3.4.v20130626-0ab9c4c]
 at com.sun.enterprise.container.common.impl.EntityManagerWrapper.find(EntityManagerWrapper.java:320) ~[container-common.jar:3.1.2.1]

日志继续,但是我只显示了它的顶部。日志的下一行是对部署在同一服务器上的WebService的调用。并且何时发生此错误,总是由调用同一服务器中部署的WebService引起的,该调用使用从数据库中找到的方法'find'在数据库中执行查找。实体管理器实例。

使用行'(EntityManager)new InitialContext()。lookup(“ java:comp / env / persistence / etc”),将实体管理器注入到@WebService注释类的@PostConstruct的bean外部。 ;'该类接收所有传入的请求,并根据请求决定应调用哪个bean。

在收到请求之后,此类立即基于请求调用相应的单例bean,并将注入的EntityManager传递到相应的bean。

我了解尝试执行该操作时EntityManager已关闭,这确实是问题所在。但是,我认为EntityManager的打开和关闭是自动进行的。显然,这种方式行不通。我也没有直接在代码中的任何地方关闭EntityManager。

我没有找到解决此问题的任何合理解决方案。我在在线资源中发现的只是可能是Glassfish的错误,并且通常可以重新启动服务器。没有什么具体的办法可以解决问题。

下面显示了我正在使用的persistence.xml文件中配置的PersistenceUnit中存在的一些信息。

<persistence-unit> name="XXX" transaction-type="JTA"
<provider>org.eclipse.persistence.jpa.PersistenceProvider></provider>
<jta-data-source>jdbc/YYY</jta-data-source>
<properties>
            <property name="eclipselink.target-database" value="Oracle"/>
            <property name="eclipselink.cache.shared.default" value="false"/>
            <property name="eclipselink.cache.size.default" value="0"/>
            <property name="eclipselink.cache.type.default" value="None"/>
            <property name="eclipselink.weaving.internal" value="false"/>
            <property name="toplink.target-database" value="Oracle"/>
            <property name="eclipselink.session.customizer"                       
            value="aaa.bbb.ccc.IsolateEmbeddablesCustomizer"/>
 </properties>
 <exclude-unlisted-classes>true</exclude-unlisted-classes>
 </persistence-unit>

您对如何解决此问题有任何想法吗,你们中的任何人也遇到相同的错误吗?

谢谢。

1 个答案:

答案 0 :(得分:0)

我认为问题就在这里:

  

实体管理器被注入Bean中的bean外部   使用以下行的@WebService注释类的@PostConstruct   '(EntityManager)新   InitialContext()。lookup(“ java:comp / env / persistence / etc”);' ...

容器从其维护的某个池中提供EntityManager个。 EM具有一定的生命周期,并且它们可能在某个时间点失效。通常(稍后解释),这将不是问题,因为通常以受控方式注入EM。

但是您只能在@PostConstruct中将其初始化为某个变量,并且当该变量所指向的EM无效时,它不会被重新初始化,或者因为它没有按预期的方式由容器进行管理。

我认为您可以通过仅检查EM是否无效并在引用无效的情况下再次执行查找来解决此问题。 但是我强调:这不是正确的方法。

  

通过注入   EntityManager到相应的bean。

请勿通过EM。在使用它的bean中初始化EM。通过唯一的一个实例,您将没有任何储蓄。相反,它会使性能变差。让容器处理创建EM的优化。

因此,通常,您将在bean中执行以下操作(不通过EM,而是在bean上进行管理):

@PersistenceContext(unitName="XXX") // "unitName" might not be needed
private EntityManeger em;           // if you use only one persistence unit

使EM受到正确管理。这样容器可以确保它始终有效。

如果您正确构造了可以让容器初始化的bean,例如将@Inject放入您的@WebService,那么这应该是可能的。

如果由于某种原因不可能,那么您仍然可以在bean中进行JNDI查找,但是我对任何JTA事务的功能都持怀疑态度。