EJB3事务传播

Mat*_* S. 26 transactions java-ee ejb-3.0

我有一个无状态的豆类似于:

@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();
    }
}
Run Code Online (Sandbox Code Playgroud)

通常用法是客户端将调用processObjects(...),它实际上不与实体管理器交互.它完成了它需要做的事情,并为每个要处理的对象单独调用进程(...).进程的持续时间(...)相对较短,但是processObjects(...)可能需要很长时间来运行所有内容.因此我不希望它维持一个开放的交易.我确实需要单独的进程(...)操作才能在自己的事务中运行.这应该是每次通话的新交易.最后,我想保持选项打开,让客户端直接调用进程(...).

我尝试了许多不同的事务类型:从不,不支持,支持(在processObjects上)和required,需要new(on 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

但我仍然很好奇是否可以在一堂课中完成这项任务.在我看来,事务管理器只在bean级别运行,即使为各个方法提供了更具体的注释.因此,如果我以某种方式标记一种方法以防止事务开始调用同一实例中的其他方法也不会创建事务,无论它们如何被标记?

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

小智 24

另一种方法是在同一个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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这样你实际上"强制" process()通过ejb代理堆栈访问该方法,因此@TransactionAttribute实现了 - 并且仍然只保留一个类.唷!