【问题标题】:JTA controlled transactions in JBoss AS7 using EclipseLink, Transaction is required使用 EclipseLink 在 JBoss AS7 中 JTA 控制事务,需要事务
【发布时间】:2012-11-14 13:16:41
【问题描述】:

环境

应用服务器:JBoss AS7 (7.1.1 Final)

JPA 实现:EclipseLink (2.4.1)

操作系统:Windows 7 数据库:PostgreSQL 8.4

更新 2,已解决

问题是我实例化了 AccountService 类,而不是使用@EJB 注入它。修复后,EntityManager 在服务中被正确检测,并且在执行em.persist(account);时有一个事务可用

更新

我做了一个最小的项目来展示我的问题。发布到 Github:

https://github.com/gotling/jboss-eclipselink-problem

我有两个可能相关的问题,由于我不了解 EJB 的正确使用。

  1. 我无法让 EnityManager 在持久性 JAR 中注入 AccountService.java,导致 NullPointerException。

  2. 如果在构造函数中将 EntityManager 发送到 AccountService,则在执行 em.persist 时找不到事务。

项目结构

EJB

  • lib/persistanceunit.jar

  • web-service.war

问题

我正在尝试让 JBoss 管理我的 Java EE 服务中的事务。问题是 EclipseLink 在尝试持久化实体时似乎没有获取 JBoss 管理的事务。

我已按照指南 https://community.jboss.org/wiki/HowToUseEclipseLinkWithAS7(备选方案 1 和备选方案 2 第 4 步)了解如何使用 EclipseLink 配置 JBoss。

设置

战争

在 web-service.war 中像这样注入实体管理器:

@WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
    @PersistenceContext(unitName="foo")
    EntityManager em;

    public void notify(Notify notify) {
        AccountService accountService = new AccountService(em);
        accountService.create(notify);
    }
}

在上面的类和服务类之间实际上有一个控制器类,其中对 Account 对象进行了转换,将其删除以缩短代码。

持久性单元

实体是这样创建的

persistanceunit.jar 中的AccountService.java

@Stateless
public class AccountService {
    private EntityManager em;

    public AccountService(EntityManager em) {
        this.em = em;
    }

    public void create(Account account) {
        em.persist(account);
    }
}

堆栈跟踪

当调用应该持久化 Account 实体的 WS 时,我在 em.persist(account);

上遇到异常

... Caused by: javax.persistence.TransactionRequiredException: JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context) at org.jboss.as.jpa.container.AbstractEntityManager.transactionIsRequired(AbstractEntityManager.java:692) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final] at org.jboss.as.jpa.container.AbstractEntityManager.persist(AbstractEntityManager.java:562) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final] at se.magos.service.AccountService.create(AccountService.java:50) [persistenceunit-0.0.1-SNAPSHOT.jar:]

问题

  1. 我已启用跟踪日志记录。 id.au.ringerc.as7.eclipselinkpersistence 不应该在日志中可见吗?

  2. 是否有可能以某种方式将 EntityManager 注入到persistanceunit.jar 内的服务类中?

  3. 这应该在哪个 JBoss / EclipseLink 版本中开箱即用?

【问题讨论】:

  • 你能发帖AccountService类吗?
  • 您确定可以使用 operator new 创建 EJB 实例吗? IMO,您应该使用@EJB AccountService accountService 注入它。
  • 有趣。不,我不确定。对 EJB 来说相当陌生。刚做了一个测试项目并上传。将更新主帖。
  • 感谢 tair,成功了!我添加了@EJB AccountService accountService;在 WS 类中,它就像一个魅力。疯狂的这个问题花了我 3 天的时间才得到解决。不过现在我知道的多了一点。

标签: jpa transactions eclipselink jboss7.x jta


【解决方案1】:

您应该使用 @TransactionManagement(TransactionManagementType.CONTAINER) 注释 bean,并使用 @TransactionAttribute(TransactionAttributeType.REQUIRED) 注释 create 方法。 第一个注解是为了让应用服务器知道事务是由容器管理的,后者是为了让方法启动一个事务,如果没有当前的事务,一旦被调用。

【讨论】:

  • 我试过了,结果没有差别。我将清理我的代码并在问题中粘贴一些附加信息。
  • 问题是在AccountService bean 中,您使用来自调用对象的实体管理器,这样就没有创建事务,您应该手动创建一个。遵循 Java EE 标准并为了让容器管理事务,应将实体管理器注入 ejb 本身。所以,只需移动 '@PersistenceContext(unitName="foo") EntityManager em;'到AccountService bean,一切都应该正常。
  • 这实际上是我开始的方式,将@PersistenceContext 放在我坚持的服务中。问题在于 EntityManger 被注入较新,可能是因为我们所有的实体类都在一个持久单元 jar 中,它在多个 WAR 文件之间共享。
  • 你的意思是你有一个包含实体源代码的通用jar?在这种情况下,您应该在使用它的每个项目中包含公共 jar,但每个 Web 或企业应用程序(即 WAR 或 EAR)都必须有自己的 persistence.xml 配置文件。
  • 我只有一个 EAR 文件,一个包含实体、服务类 (AccountService) 和persistance.xml 的通用 jar。这个 jar 放在 EAR:s lib 目录中,并在 EAR 中打包的 WAR:s 之间共享。我虽然一个EAR 应该只有一个persistence.xml。无论如何,在公共 jar(持久性单元)中使用 @PersistenceContext 失败,em is not beeeing set,导致在执行 em.persist() 时出现 NullPointerException。
【解决方案2】:

问题是 AccountService 类是实例化的,而不是使用 @EJB 注释注入的。修复后,EntityManager 被正确注入到服务中,并且在执行 em.persist(account); 时事务可用;

之前

@WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
    @PersistenceContext(unitName="foo")
    EntityManager em;

    public void notify(Notify notify) {
        AccountService accountService = new AccountService(em);
        accountService.create(notify);
    }
}

之后

@WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
    @PersistenceContext(unitName="foo")
    EntityManager em;

    @EJB
    AccountService accountService;

    public void notify(Notify notify) {
        accountService.create(notify);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    • 2011-12-10
    • 2012-05-24
    • 1970-01-01
    • 1970-01-01
    • 2015-02-04
    相关资源
    最近更新 更多