4

我们在一个主要由 Jboss Forge 生成的应用程序中使用 Jboss 7.1.1,但是我们为所有与域相关的代码添加了一个存储库层。

我试图创建一个启动 bean 来初始化数据库状态。我想为此使用我现有的存储库。

我的存储库都有一个扩展的 PersistenceContext 注入其中。我从我的视图 bean 中使用这些 @ConversationScoped @Stateful bean,通过使用扩展上下文,我的实体在对话期间保持管理。

首先我尝试了这个:

@Startup
@Singleton
public class ConfigBean {

    @Inject
    private StatusRepository statusRepository;

    @Inject
    private ZipCode zipCodeRepository;

    @PostConstruct
    public void createData() {
        statusRepository.add(new Status("NEW"));
        zipCodeRepository.add(new ZipCode("82738"));
    }

}

Example repository:
@Stateful
public class ZipCodeRepository {

    @PersistenceContext(PersistenceContextType.EXTENDED)
    private EntityManger em;

    public void add(ZipCode zipCode) {
        em.persist(zipCode);
    }

    ....
}

这最终会在应用程序启动时抛出 javax.ejb.EJBTransactionRolledbackException,并显示以下消息:

JBAS011437:在 SFSB 调用调用堆栈中找到扩展的持久性上下文,但无法使用,因为事务已经有一个与之关联的事务上下文。这可以通过更改应用程序代码来避免,或者消除扩展的持久性上下文或事务上下文。请参阅 JPA 规范 2.0 第 7.6.3.1 节。

我很难找到一个很好的解释,实际上认为由于 EJB 及其注入是由代理处理的,所有 PersistenceContext 注入和传播都将自动处理。我想我错了。

然而,在这个想法的过程中,我尝试了以下方法:

@Startup
@Singleton
public class ConfigBean {

    @Inject
    private SetupBean setupBean;

    @PostConstruct
    public void createData() {
        setupBean.createData();
    }

    @Stateful
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public static class SetupBean {

        @Inject
        private StatusRepository statusRepository;

        @Inject
        private ZipCode zipCodeRepository;

        public void createData() {
            statusRepository.add(new Status("NEW"));
            zipCodeRepository.add(new ZipCode("82738"));
        }
    }
}

这可以解决问题。我所做的只是将代码包装在一个有状态的 SessionBean 中,它是我的 Singleton bean 的静态内部类。

有人理解这种行为吗?因为虽然现在一切正常,但我仍然有点疏远它为什么会这样工作。

4

1 回答 1

3
  • 容器管理的扩展持久性上下文只能在有状态会话 bean 的范围内启动。它从创建声明对 PersistenceContextType.EXTENDED 类型的实体管理器的依赖关系的有状态会话 bean 开始存在,并且被称为绑定到有状态会话 bean。

从发布的代码来看,它ZipCodeRepository本身似乎不是有状态的 bean,但您是从一个这样的 bean 调用它的。

在这种情况下,您是PersistenceContextType.TRANSACTION从& 通过拥有ConfigBean & 传播的,它试图加入交易,因此是例外。ZipCodeRepositoryPersistenceContextType.EXTENDED

  • 调用使用 PersistenceContextType.EXTENDED 定义的实体管理器将导致使用绑定到该组件的现有扩展持久性上下文。

  • 当有状态会话bean的业务方法被调用时,如果有状态会话bean使用容器管理的事务划分,并且实体管理器尚未与当前的JTA事务关联,则容器将实体管理器与当前的JTA事务关联并调用EntityManager.joinTransaction。如果已经存在与 JTA 事务相关联的不同持久性上下文,则容器将抛出 EJBException。

而在后一种情况下,您SetupBean将为每个TransactionAttributeType.REQUIRES_NEW扩展类型的调用创建一个新事务,因为它是一个有状态的 bean。

因此,SetupBean为每次调用和以后的调用添加为有状态会话 bean 启动新事务ZipCodeRepository不会导致异常。ZipCodeRepository将加入由 发起的同一事务SetupBean

于 2013-03-05T08:26:03.243 回答