已经在ejb内部打开新事务

时间:2016-02-09 08:58:01

标签: java transactions 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
    }

}

方法foo从ejb外部调用。我希望每个id都在自己的事务中执行,这样数据get就会直接保存到数据库中。在本课程之外不可能有foreach。我想知道最好的方法是什么?目前我再次注入接口,跨越ejb边界(以便对TransactionAttribute get进行评估)。

3 个答案:

答案 0 :(得分:1)

关于循环引用的方法非常好。允许在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,从而加快完成任务。

答案 1 :(得分:0)

你真的必须在一个班级中拥有这两种方法吗?您可以将bar()移动到自己的bean并使其成为事务性的。然后你不必使用这种自我注射。

答案 2 :(得分:-2)

您也可以尝试使用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);
    }
}