调用entityManager.getTransaction()时的EJBException

时间:2011-06-23 09:20:17

标签: java hibernate jpa transactions ejb-3.0

这可能是微不足道的,但我会喜欢一些帮助。

我明白了:

 javax.ejb.EJBException: java.lang.IllegalStateException: Illegal to call this method from injected, managed EntityManager 
 11:54:37,105 ERROR [STDERR] at org.jboss.ejb3.tx.Ejb3TxPolicy.handleExceptionInOurTx(Ejb3TxPolicy.java:77)
 11:54:37,105 ERROR [STDERR] at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:83)
 11:54:37,105 ERROR [STDERR] at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:190)

做的时候:

@PersistenceContext(unitName = "someName")
private EntityManager em;

...

final EntityManager entityManager = getEntityManager();
final EntityTransaction tx = entityManager.getTransaction(); // here

谁能告诉我原因可能是什么?

2 个答案:

答案 0 :(得分:19)

在Java EE托管上下文中获取与EntityManager关联的EntityTransaction实例的引用是非法的。来自EntityManager.getTransaction()的Java EE API文档:

  

返回资源级EntityTransaction对象。该   可以使用EntityTransaction实例   串行开始并提交多个   交易。

Returns:
    EntityTransaction instance 
Throws:
    IllegalStateException - if invoked on a JTA entity manager

最后一行与此相关。

使用@PersistenceContext或@Inject注释将EntityManager注入部署在应用程序服务器上的EJB时,EntityManager将由容器管理,而不是由应用程序管理。容器管理实体管理器必须是JTA实体管理器;应用程序管理的实体管理器可以是资源本地实体管理器。这取决于JPA规范:

  

实体经理的基础   交易是通过控制的   JTA被称为JTA实体经理。

     

实体经理的基础   交易由   申请通过   EntityTransaction API被称为a   资源本地实体经理。

     

容器管理的实体管理器   必须是JTA实体经理。 JTA   实体经理仅指定用于   在Java EE容器中使用。

从第一点开始(关于IllegalStateException),您不得获取容器注入的EntityManagers的EntityTransaction引用。但是,如果容器只注入了EntityManagerFactory,并且您的应用程序通过调用EntityManagerFactory.getEntityManager获取了EntityManager引用,则可以这样做。

此外,应该注意的是,调用EntityManager.getTransaction()对于JTA实体管理器来说毫无意义。这由JPA规范在EntityTransaction接口的定义中表示:

  

EntityTransaction接口用于控制资源本地实体管理器上的资源事务。

关于管理JTA事务本身的主题,如果您需要自己管理事务边界(即使用bean管理的事务),请注入UserTransaction实例。或者,如果您希望容器管理事务,则只需使用适当的TransactionalAttribute值注释方法或bean。

在应用程序服务器中使用资源本地实体管理器(和数据源)与bean托管或容器管理事务通常不是一个好主意,但是可以这样做。

您将找到一个合适的示例,演示如何在Hibernate EntityManager documentation中注入EntityManager来使用BMT。如果您已经注释了bean类或方法,那么CMT就更加微不足道了;你只需要避免调用CMT的getEntityTransaction()方法就可以了。

如果您希望进一步了解,我建议您阅读JPA 2.0规范的第7章,标题为“实体管理器和持久性上下文”。本章提供的示例证明:

  • 如何在应用服务器(通常是使用它们的地方)中使用JTA实体管理器。
  • 如何在应用程序服务器中使用资源本地实体管理器。
  • 如何在Java SE应用程序中使用资源本地实体管理器。

答案 1 :(得分:3)

您不需要手动实例化EntityManager,因为您的容器会为您执行此操作  @PersistenceContext注释。此外,您不需要手动开始交易,也可以由您的收件人提供。只需使用您的em字段,忘记其他字段。