Java EE 7 - 如何从容器内部启动事务?
Java EE 7 - How start a transaction from inside a container?
我正在使用 Java EE 7 + GlassFish,并且需要对无状态 bean 中的许多 JPA 实体执行一些操作。
@Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
///do some work against entity
}
}
}
这个 JobRunner bean 被注入到 servlet 中,我从网络调用 do() 方法 UI。
问题是所有实体都在一个事务中被更改,因此如果一个事务失败,所有内容都会回滚,这是不希望的。有没有办法为每个实体(即循环的每次迭代)启动和关闭新事务?
我可以编写一个外部客户端并在其中创建一个循环,为每个实体调用一个无状态 bean,但这对我来说并不是完全可行的,因为我更喜欢保持应用程序单一。我能以某种方式管理容器内的事务表单吗?
也许 JMS 有帮助?如果我将执行者实现为消息侦听器并将为每个实体发送一条消息,它会为每个实体启动一个新事务吗?
@Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
sendMessageToRealDoer(entity);
}
}
}
创建另一个 bean,在方法或 bean 级别指定 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
:
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
@Stateless
public class JobWork {
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void doWork(Entity entity) {
// do what you would do in the loop with the Entity
// this runs in a new transaction
}
}
我希望我能告诉你,你只需要注释同一个 bean (JobRunner
) 的方法并简单地调用它。这是不可能的 (EDIT)without workarounds - 检查 Steve C(/EDIT) 的评论,因为在 EJB 和 CDI bean 中调用 this
对象的方法时,拦截器不会得到叫。在这两种情况下,事务都是用拦截器实现的。
一些注意事项:
- 如果预期循环中操作的总持续时间很长,您将在 outer 事务中获得超时,该事务隐式启动
JobRunner
无状态 EJB。您需要采取措施确保没有 "outer" 事务启动。
- 将数据发送到队列也可以;但是队列将异步处理它们,这意味着执行将 return 到 servlet 调用
JobRunner.do()
很可能在所有项目都被处理之前。
我正在使用 Java EE 7 + GlassFish,并且需要对无状态 bean 中的许多 JPA 实体执行一些操作。
@Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
///do some work against entity
}
}
}
这个 JobRunner bean 被注入到 servlet 中,我从网络调用 do() 方法 UI。
问题是所有实体都在一个事务中被更改,因此如果一个事务失败,所有内容都会回滚,这是不希望的。有没有办法为每个实体(即循环的每次迭代)启动和关闭新事务?
我可以编写一个外部客户端并在其中创建一个循环,为每个实体调用一个无状态 bean,但这对我来说并不是完全可行的,因为我更喜欢保持应用程序单一。我能以某种方式管理容器内的事务表单吗?
也许 JMS 有帮助?如果我将执行者实现为消息侦听器并将为每个实体发送一条消息,它会为每个实体启动一个新事务吗?
@Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
sendMessageToRealDoer(entity);
}
}
}
创建另一个 bean,在方法或 bean 级别指定 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
:
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
@Stateless
public class JobWork {
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void doWork(Entity entity) {
// do what you would do in the loop with the Entity
// this runs in a new transaction
}
}
我希望我能告诉你,你只需要注释同一个 bean (JobRunner
) 的方法并简单地调用它。这是不可能的 (EDIT)without workarounds - 检查 Steve C(/EDIT) 的评论,因为在 EJB 和 CDI bean 中调用 this
对象的方法时,拦截器不会得到叫。在这两种情况下,事务都是用拦截器实现的。
一些注意事项:
- 如果预期循环中操作的总持续时间很长,您将在 outer 事务中获得超时,该事务隐式启动
JobRunner
无状态 EJB。您需要采取措施确保没有 "outer" 事务启动。 - 将数据发送到队列也可以;但是队列将异步处理它们,这意味着执行将 return 到 servlet 调用
JobRunner.do()
很可能在所有项目都被处理之前。