在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开始。

09-20 12:44