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

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

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

  1. 创建几个域对象并通过DAO保留它们
  2. 调用服务方法以启动作业
  3. 等到作业完成
  4. 使用DAO检索域对象并检查其状态

显然,以上所有内容都应该在一个事务中执行,但不幸的是, 事务不会传播到新线程 (我理解这背后的基本原理)。

我想到的想法:

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

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

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

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

资料来源: Spring程序化交易 。

例:

 @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); } } 

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

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