繁体   English   中英

已经在ejb内时打开新交易

[英]Open new transaction when already inside ejb

请考虑以下情况:

@Stateless
@Clustered
public class FacadeBean implements Facade {

    @EJB
    private Facade facade;

    @Override
    public void foo(List<Integer> ids) {
        // read specific id's from the db
        for (Integer id : ids) {
            facade.bar(id);
        }
    }

    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void bar(Integer id) {
        // save something to the db
    }

}

从ejb外部调用方法foo。 我希望每个id在自己的事务中执行,以便数据直接保存到数据库中。 此类之外的foreach是不可能的。 我想知道什么是最好的方法吗? 此刻,我再次注入接口,以跨过ejb边界(以便对TransactionAttribute进行评估)。

您关于循环参考的方法非常好。 允许在EJB中进行循环引用。 为了开始新的事务或@Asynchronous线程,这甚至是必需的(否则,当前线程仍会阻塞)。

@Stateless
public class SomeService {

    @EJB
    private SomeService self; // Self-reference is perfectly fine.


    // Below example starts a new transaction for each item.

    public void foo(Iterable<Long> ids) {
        for (Long id : ids) {
            self.fooInNewTransaction(id);
        }
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void fooInNewTransaction(Long id) {
        // ...
    }


    // Below example fires an async thread in new transaction.

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void bar(Iterable<Long> ids) {
        for (Long id : ids) {
            self.fooAsynchronously(id);
        }
    }

    @Asynchronous
    public void fooAsynchronously(Long id) {
        // ...
    }

}

仅在较旧的容器中,此方法不起作用,最显着的是带有古老EJB 3.0 API的JBoss AS 5。 这就是为什么人们发明了诸如SessionContext#getBusinessObject()类的变通方法,甚至是通过JNDI手动抓取的原因。

这些天这些都是不必要的。 这些是解决方法,而不是解决方案。

我个人只会以相反的方式进行交易。 显然, foo()方法从不打算进行事务处理。

@Stateless
public class SomeService {

    @EJB
    private SomeService self;

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void foo(Iterable<Long> ids) {
        for (Long id : ids) {
            self.foo(id);
        }
    }

    public void foo(Long id) {
        // ...
    }

}

根据具体的功能要求,您甚至可以使foo(Long id) @Asynchronous ,从而加快任务的执行速度。

您真的必须在一个类中同时使用这两种方法吗? 您可以将bar()移到自己的bean上并使其具有事务性。 然后,您不必使用这种自我注入。

您也可以尝试使用SessionContext#getBusinessObject()方法。

@Resource
SessionContext sessionContext;

@Override
public void foo(List<Integer> ids) {
    Facade facade = sessionContext.getBusinessObject(Facade.class);
    // read specific id's from the db
    for (Integer id : ids) {
        facade.bar(id);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM