Transactions EJB3事务传播

Transactions EJB3事务传播,transactions,jakarta-ee,ejb-3.0,Transactions,Jakarta Ee,Ejb 3.0,我有一个无状态bean,类似于: @Stateless public class MyStatelessBean implements MyStatelessLocal, MyStatelessRemote { @PersistenceContext(unitName="myPC") private EntityManager mgr; @TransationAttribute(TransactionAttributeType.SUPPORTED) public

我有一个无状态bean,类似于:

@Stateless
public class MyStatelessBean implements MyStatelessLocal, MyStatelessRemote {
    @PersistenceContext(unitName="myPC")
    private EntityManager mgr;

    @TransationAttribute(TransactionAttributeType.SUPPORTED)
    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.process(obj);
        }
    }

    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}
@无状态
公共类MyStatelessBean实现MyStatelessLocal、MyStatelessRemote{
@PersistenceContext(unitName=“myPC”)
私人机构经理;
@TransactionAttribute(TransactionAttribute.SUPPORTED)
公共void processObjects(列表对象){
//此方法只处理数据,不需要事务
用于(对象对象对象:对象对象对象){
本程序(obj);
}
}
@TransactionAttribute(TransactionAttributeType.REQUIRES\u NEW)
公共作废流程(对象obj){
//对必须在事务范围内的obj执行一些工作
本经理合并(obj);
// ...
本经理合并(obj);
// ...
this.mgr.flush();
}
}
通常情况下,客户端会调用processObjects(…),它实际上不会与实体管理器进行交互。它做它需要做的事情,并为每个要处理的对象分别调用process(…)。进程(…)的持续时间相对较短,但processObjects(…)可能需要很长的时间来运行所有内容。因此,我不希望它保持一个开放的交易。我确实需要单个进程(…)操作在它们自己的事务中运行。这应该是每个调用的新事务。最后,我想让客户端直接调用进程(…)的选项保持打开状态

我尝试了许多不同的事务类型:从不、不支持、支持(在processObjects上)和必需、需要新建(在process上),但每次调用merge()时我都会得到TransactionRequiredException

通过将这些方法分成两个不同的bean,我已经能够使其工作:

@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
    @EJB
    private MyStatelessBean2 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }
}

@Stateless
public class MyStatelessBean2 implements MyStatelessLocal2, MyStatelessRemote2 {
    @PersistenceContext(unitName="myPC")
    private EntityManager mgr;

    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}
@无状态
@TransactionAttribute(不支持TransactionAttribute类型)
公共类MyStatelessBean1实现MyStatelessLocal1、MyStatelessRemote1{
@EJB
私人MyStatelessBean2 myBean2;
公共void processObjects(列表对象){
//此方法只处理数据,不需要事务
用于(对象对象对象:对象对象对象){
这个.myBean2.过程(obj);
}
}
}
@无国籍
公共类MyStatelessBean2实现MyStatelessLocal2、MyStatelessRemote2{
@PersistenceContext(unitName=“myPC”)
私人机构经理;
@TransactionAttribute(TransactionAttributeType.REQUIRES\u NEW)
公共作废流程(对象obj){
//对必须在事务范围内的obj执行一些工作
本经理合并(obj);
// ...
本经理合并(obj);
// ...
this.mgr.flush();
}
}
但我仍然很好奇是否有可能在一节课上完成这一点。在我看来,事务管理器只在bean级别上运行,即使给单个方法提供了更具体的注释。因此,如果我以某种方式标记一个方法以防止事务开始调用同一实例中的其他方法,那么无论它们如何标记,也不会创建事务


我正在使用JBoss Application Server 4.2.1.GA,但欢迎/首选非特定答案。

我认为与方法processObjects上的@TransactionAttribute(TransactionAttribute.Never)有关

TransactionAttributeType.Never

如果客户机正在 事务并调用企业 在bean的方法中,容器抛出 远程异常。如果客户不是 与事务关联的 容器不启动新的 在运行该方法之前执行事务

我假设您是客户机代码中的方法processObjects。因为您的客户机可能与某个事务没有关联,所以使用TransactionaAttribute Type.Never的方法调用从一开始就不快乐。然后从processObjects调用process方法,尽管具有TransactionAttributeType。Required注释不是bean方法调用,并且不强制执行事务策略。调用merge时会出现异常,因为您仍然没有与事务关联


尝试使用TransactionAttribute Type。两种bean方法都需要,看看它是否奏效。

Matt,值得一提的是,我得出了与您完全相同的结论

TransactionAttributeType仅在跨越Bean边界时考虑。当在同一bean中调用方法时,TransactionattributeType没有效果,无论方法上放置了什么类型

就我所见,EJB持久性规范中没有任何内容指定在这些情况下应该采取什么行为


我在Jboss中也经历过这种情况。我还将在Glassfish中尝试一下,并让您知道结果。

我认为每个bean都封装在一个代理中,该代理控制事务行为。当您从一个bean调用另一个bean时,您将通过该bean的代理进行调用,代理可以更改事务行为


但是,当一个bean使用不同的事务属性在其自身上调用一个方法时,该调用不会通过代理进行,因此行为不会改变。

另一种方法是在同一个bean上同时使用两个方法,并对自身进行
@EJB
引用!诸如此类:

// supposing processObjects defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
    @EJB
    private MyStatelessLocal1 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }


    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}
//假设在MyStatelessRemote1上定义了ProcessObject,而在MyStatelessLocal1上定义了进程
@无国籍
@TransactionAttribute(不支持TransactionAttribute类型)
公共类MyStatelessBean1实现MyStatelessLocal1、MyStatelessRemote1{
@EJB
私人MyStatelessLocal1 myBean2;
公共void processObjects(列表对象){
//此方法只处理数据,不需要事务
用于(对象对象对象:对象对象对象){
这个.myBean2.过程(obj);
}
}
@Tr
// supposing processObjects defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {

    @Resource
    private SessionContext ctx;

    @EJB
    private MyStatelessLocal1 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }


    public void process(Object obj) {

        UserTransaction tx = ctx.getUserTransaction();

        tx.begin();

        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();

        tx.commit();
    }
}