Java EE 7 - 如何从容器内部启动事务?

问题描述 投票:0回答:1

我正在使用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);
            }
    }
}
java java-ee transactions ejb
1个回答
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)并简单地调用它。这是不可能的(编辑)没有变通方法 - 检查Steve C(/ EDIT)的评论,因为在EJB和CDI bean中调用this对象的方法时,拦截器不会被调用。在两种情况下都使用拦截器实现事务。

一些说明:

  • 如果预期循环中操作的总持续时间很长,那么外部事务中将获得超时,这是针对JobRunner无状态EJB隐式启动的。您将需要采取不启动“外部”事务的措施。
  • 将数据发送到队列也会起作用;但是队列将异步处理它们,这意味着执行将在所有项目处理之前最有可能返回到调用JobRunner.do()的servlet。
© www.soinside.com 2019 - 2024. All rights reserved.