How to propagate Spring transaction to another thread?

爱⌒轻易说出口 提交于 2019-12-30 07:03:16

问题


Perhaps, I am doing something wrong, but I can't find a good way out for the following situation.

I would like to unit test a service that uses Spring Batch underneath to execute jobs. The jobs are executed via pre-configured AsyncTaskExecutor in separate threads. In my unit test I would like to:

  1. Create few domain objects and persist them via DAO
  2. Invoke the service method to launch the job
  3. Wait until the job is completed
  4. Use DAO to retrieve domain objects and check their state

Obviously, all above should be executed within one transaction, but unfortunately, transactions are not propagated to new threads (I understand the rationale behind this).

Ideas that came to my mind:

  • Commit the transaction#1 after step (1). Is not good, as the DB state should be rolled back after the unit test.
  • Use Isolation.READ_UNCOMMITTED in job configuration. But this requires two different configurations for test and for production.

回答1:


I think the simplest solution would be configure the JobLauncher with a SyncTaskExecutor during test execution - this way the job is executed in the same thread as the test and shares the transaction.

The task executor configuration can be moved to a separate spring configuration xml file. Have two versions of it - one with SyncTaskExecutor which is used during testing and the other AsyncTaskExecutor that is used for production runs.




回答2:


Although this is not a true solution to your question, I found it possible to start a new transaction inside a worker thread manually. In some cases this might be sufficient.

Source: Spring programmatic transactions.

Example:

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



回答3:


If you do want separate configurations, I'd recommend templating the isolation policy in your configuration and getting its value out of a property file so that you don't wind up with a divergent set of Spring configs for testing and prod.

But I agree that using the same policy production uses is best. How vast is your fixture data, and how bad would it be to have a setUp() step that blew away and rebuilt your data (maybe from a snapshot, if it's a lot of data) so that you don't have to rely on rollbacks?



来源:https://stackoverflow.com/questions/5232351/how-to-propagate-spring-transaction-to-another-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!