我正在使用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有帮助吗?如果我将doer实现为消息监听器并将为每个实体发送消息,它是否会为每个实体启动一个新事务?
@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
)并简单地调用它。这是不可能的(编辑)没有变通方法 - 检查Steve C(/ EDIT)的评论,因为在EJB和CDI bean中调用this
对象的方法时,拦截器不会被调用。在两种情况下都使用拦截器实现事务。
一些说明:
JobRunner
无状态EJB隐式启动的。您将需要采取不启动“外部”事务的措施。JobRunner.do()
的servlet。