我们在一个主要由 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 的静态内部类。
有人理解这种行为吗?因为虽然现在一切正常,但我仍然有点疏远它为什么会这样工作。