我在使用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>
您对如何解决此问题有任何想法吗,你们中的任何人也遇到相同的错误吗?
谢谢。
答案 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事务的功能都持怀疑态度。