如何将Spring事务传播到另一个线程?

时间:2011-03-08 12:19:52

标签: java multithreading spring transactions propagation

也许,我做错了什么,但我找不到适合下列情况的好方法。

我想对使用下面的Spring Batch执行作业的服务进行单元测试。作业通过预先配置的AsyncTaskExecutor在不同的线程中执行。在我的单元测试中,我想:

  1. 创建少量域对象并通过DAO
  2. 保留它们
  3. 调用服务方法以启动作业
  4. 等到作业完成
  5. 使用DAO检索域对象并检查其状态
  6. 显然,以上所有内容都应该在一次交易中执行,但不幸的是,transactions are not propagated to new threads(我理解这背后的理由)。

    我想到的想法:

    • 在步骤(1)之后提交事务#1。不好,因为在单元测试后应该回滚DB状态。
    • 在作业配置中使用Isolation.READ_UNCOMMITTED。但这需要两种不同的配置用于测试和生产。

3 个答案:

答案 0 :(得分:3)

虽然这不是您问题的真正解决方案,但我发现可以手动在工作线程中启动 new 事务。在某些情况下,这可能就足够了。

来源:Spring programmatic transactions

示例:

@PersistenceContext
private EntityManager entityManager;
@Autowired
private PlatformTransactionManager txManager;

/* in a worker thread... */
public void run() {
    TransactionStatus tx = txManager.getTransaction(new DefaultTransactionDefinition());
    try {
        entityManager.find(...)
        ...
        entityManager.flush(...)
        etc...
        txManager.commit(tx);
    } catch (RuntimeException e) {
        txManager.rollback(tx);
    }
}

答案 1 :(得分:2)

我认为最简单的解决方案是在测试执行期间使用SyncTaskExecutor配置JobLauncher - 这样就可以在与测试相同的线程中执行作业并共享事务。

可以将任务执行程序配置移动到单独的spring配置xml文件中。有两个版本 - 一个是在测试期间使用的SyncTaskExecutor,另一个是用于生产运行的AsyncTaskExecutor。

答案 2 :(得分:1)

如果您确实需要单独的配置,我建议您在配置中模板化隔离策略,并从属性文件中获取其值,这样您就不会使用一组不同的Spring配置进行测试和生成。

但我同意使用相同的政策生产用途是最好的。您的夹具数据有多大,以及有setUp()步骤可以吹走并重建您的数据(可能来自快照,如果它是大量数据)有多么糟糕,这样您就不必依靠回滚?