我正在使用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中,然后从Web UI调用do()方法。
问题在于,所有实体都将在一个事务中更改,因此如果一个实体失败,则所有内容都会回退,这是不希望的。是否有一种方法可以为每个实体(即循环的每次迭代)启动和关闭新交易?
我可以编写一个外部客户端,并在其中创建一个循环,为每个实体调用无状态Bean,但这并不是完全对我有用的,因为我更喜欢保持应用程序的整体性。我可以以某种方式管理容器内的交易表格吗?
也许JMS有帮助?如果我将执行者作为消息侦听器实现并将为每个实体发送一条消息,它将为每个实体启动新的交易吗?
@Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
sendMessageToRealDoer(entity);
}
}
}
答案 0 :(得分:2)
在方法或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
)的方法并简单地调用它即可。这是不可能的(至少是我上次尝试的时间),因为在EJB和CDI bean中调用this
对象的方法时,不会调用拦截器。两种情况下都使用拦截器实现事务。
一些注意事项:
JobRunner
无状态EJB是隐式启动的。您将需要采取措施以确保没有“外部”交易开始。JobRunner.do()
的servlet。