Singleton中的PersistenceContextType.EXTENDED

时间:2013-03-04 15:16:08

标签: jpa-2.0 jboss7.x java-ee-6 ejb-3.1 entitymanager

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

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

我的存储库都有一个扩展的PersistenceContext注入其中。我使用@ConversationScoped @Stateful bean的View 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);
    }

    ....
}

这最终会在Application启动时抛出一个javax.ejb.EJBTransactionRolledbackException,并显示以下消息:

  

JBAS011437:在SFSB调用堆栈中找到扩展持久性上下文但由于事务已经有一个与之关联的事务上下文,因此无法使用。通过更改应用程序代码可以避免这种情况,或者消除扩展的持久性上下文或事务上下文。参见JPA spec 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"));
        }
    }
}

这就是诀窍。我所做的就是将代码包装在Stateful SessionBean中,这是我的Singleton bean的静态内部类。

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

1 个答案:

答案 0 :(得分:3)

  
      
  • 只能启动容器管理的扩展持久性上下文   在有状态会话bean的范围内。它存在于这一点上   在哪个有状态会话bean声明依赖于   创建了PersistenceContextType.EXTENDED类型的实体管理器,并且   据说被绑定到有状态会话bean。
  •   

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

在这种情况下,您从PersistenceContextType.TRANSACTION&发起ConfigBean通过ZipCodeRepository获得PersistenceContextType.EXTENDED&它试图加入事务,因此例外。

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

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

  •   

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

因此,添加ZipCodeRepository作为有状态会话bean,为每个调用启动新事务&稍后调用ZipCodeRepository不会导致异常。 SetupBean将加入由{{1}}启动的同一交易。