在TomEE(对于容器管理的事务而言更是如此)中,我想执行一个子请求,并在当前请求中使用其输出,但是两者必须属于同一事务。欢迎所有人(甚至是大胆的想法,但最好仅使用标准API而不是特定于TomEE的方法)来做到这一点。
最佳答案
这个stackoverflow问题提供了一个提示来回答我的问题:Acessing Remote/Local Session Beans
多亏了一位同事,我才能通过以下方式与TomEE合作:
结构是具有两个Web应用程序和一个接口jar:
AppA。公开调用无状态的RESTfull Web服务
会话Bean(BeanA),可重用AppB中的无状态会话Bean。
这是作为WAR构建的。
AppB。公开无状态会话bean
BeanB。这是作为WAR构建的。
AppBItf。包含本地接口
BeanB。这是作为JAR构建的,将在AppA之间共享
和AppB。
AppA的内容
在AppA中,我们有三件事:REST服务,Bean及其本地接口。
RestService.java
import javax.ejb.EJB;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
@Path("/RestService/")
public class RestService
{
@EJB
BeanALocal bean;
@GET
@Path("/doInTransaction")
public Response doInTransaction() {
return Response.ok().entity("Transaction result: " + bean.doInTransaction()).build();
}
}
BeanA.java
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.transaction.TransactionSynchronizationRegistry;
import BeanBLocal;
@Stateless
@LocalBean
public class BeanA implements BeanALocal
{
@EJB
BeanBLocal beanB;
@Resource
TransactionSynchronizationRegistry txReg;
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public String doInTransaction() {
return "Transaction: " + txReg.getTransactionKey() + "; BeanB: " + beanB.doInTransaction();
}
}
BeanALocal.java
import javax.ejb.Local;
@Local
public interface BeanALocal {
String doInTransaction();
}
AppB的内容
它仅包含Bean(其本地接口在AppBItf中定义):
BeanB.java
import javax.annotation.Resource;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.transaction.TransactionSynchronizationRegistry;
@Stateless
@LocalBean
public class BeanB implements BeanBLocal
{
@Resource
TransactionSynchronizationRegistry txReg;
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public String doInTransaction() {
return "BeanB: Transaction: " + txReg.getTransactionKey();
}
}
AppBItf的内容
它仅包含BeanB的本地接口:
BeanBLocal.java
import javax.ejb.Local;
@Local
public interface BeanBLocal {
String doInTransaction();
}
部署方式
可以简单地将两个WAR(AppA.war和AppB.war)部署到Web应用程序,但是需要将JAR(AppBItf)添加到公共类加载器(common.loader)。
结果
在上面的代码中,BeanB带有TransactionAttributeType.REQUIRED注释。调用REST服务(即在http://localhost:8080/AppA/RestService/doInTransaction上执行GET)将得到以下输出:
[Xid:globalId=1000000047544d4944,length=64,branchId=0,length=64];
[Xid:globalId=1000000047544d4944,length=64,branchId=0,length=64]
请注意,第一个和第二个事务ID相同,因此BeanB重用了BeanA的事务。这就是我所需要的。
当我将注释更改为TransactionAttributeType.REQUIRES_NEW时,容器会自动启动BeanB的新事务:
[Xid:globalId=1000000047544d4944,length=64,branchId=0,length=64];
[Xid:globalId=2000000047544d4944,length=64,branchId=0,length=64]
第一笔交易的ID以1开始,而第二笔交易的ID以2开始。