Java EE 7-如何从容器内部开始事务?

时间:2019-04-15 22:24:57

标签: java java-ee transactions ejb

我正在使用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);
            }
    }
}

1 个答案:

答案 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对象的方法时,不会调用拦截器。两种情况下都使用拦截器实现事务。

一些注意事项:

  • 如果循环中操作的总持续时间预计会很长,那么您将在 outer 事务中获得一个超时,该超时对于JobRunner无状态EJB是隐式启动的。您将需要采取措施以确保没有“外部”交易开始。
  • 将数据发送到队列也可以;但是队列将异步处理它们,这意味着执行将最有可能在处理完所有项目之前返回到调用JobRunner.do()的servlet。