如何在 运行 一项长期任务之前完成容器管理的事务?

How to finish a container-managed transaction before running a long task?

我有一个任务包含 3 个步骤 prepareexecuteupdateprepareupdate 需要在事务中工作,而 execute 需要很长时间(即几分钟到几小时)。该任务是 EJB 的一部分,即:

@Stateless
public class Task {
    public void doTask() {
        prepare();
        execute();
        update();
    }
}

我的问题是,是否有一种(优雅的)方法可以在 prepare 之后提交和完成事务并在 update 之前开始一个新事务?我宁愿使用容器管理的事务,也可能不会切换到使用 UserTransaction

如果获得任何优势,可以将任务拆分为单个 EJB,但请注意暂停 execute 的事务(即使用 @Transactional(TxType.NOT_SUPPORTED) 是不够的,因为这仍然会触发超时.

我试图将其拆分为 TaskExecute class,其中包含 @Asynchronous @Transactional(NOT_SUPPORTED) public void execute() 并在完成后发送一个事件。但这似乎也不起作用。

有办法吗?


经过一些进一步的测试让我得出结论:亚历山大的回答是绝对正确的。我的理解必须改变。首先,我不知道 @Transactional 不适用于 EJB,而只能用于 CDI bean。对于 EJB,注释称为 @TransactionAttribute 并且可以设置为基本相同的值。 @Asynchronous@TransactionAttribute(NOT_SUPPORTED) 的组合确实有效(如果不等待结果)。

这取决于您要使用的 Java EE 版本。以下是三种可能的解决方案。

  • 使用 JMS,发送适当的消息并在 MDB 中执行 execute(任何版本,但需要完整配置文件)
  • 使用 Java EE 6.0 的定时器服务并安排任务以异步方式执行 execute (@Timeout)
  • 使用 Java EE 7.0 的批处理 API 安排适当的长 运行 批处理作业。

后者可能是您要查找的内容,但仅在 Java EE 7.0 及更高版本中可用。否则,JMS 解决方案是最干净的,但如果 JMS 不是一个选项,定时器服务应该可以工作。