当已经在 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 在其自己的事务中执行,以便数据直接保存到数据库中。在这个 class 之外不可能有 foreach。我想知道最好的方法是什么?目前我正在再次注入接口,以跨过 ejb 边界(以便对 TransactionAttribute 进行评估)。
您真的必须将两种方法合而为一吗class?您可以将 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);
}
}
您对循环引用的处理方式非常好。 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) {
// ...
}
}
仅在较旧的容器中,这不起作用,最显着的是 JBoss AS 5 与古老的 EJB 3.0 API。这就是为什么人们发明了 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
,从而加快任务速度。
考虑以下情况:
@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 在其自己的事务中执行,以便数据直接保存到数据库中。在这个 class 之外不可能有 foreach。我想知道最好的方法是什么?目前我正在再次注入接口,以跨过 ejb 边界(以便对 TransactionAttribute 进行评估)。
您真的必须将两种方法合而为一吗class?您可以将 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);
}
}
您对循环引用的处理方式非常好。 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) {
// ...
}
}
仅在较旧的容器中,这不起作用,最显着的是 JBoss AS 5 与古老的 EJB 3.0 API。这就是为什么人们发明了 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
,从而加快任务速度。