How to propagate a Spring transaction to another thread?

Maybe I'm doing something wrong, but I can’t find a good way out for the next situation.

I would like a unit test service that uses Spring Batch to complete tasks. Jobs run through the pre-configured AsyncTaskExecutor in separate threads. In my unit test, I would like:

  • Create multiple domain objects and save them through the DAO
  • Calling a service method to start a job
  • Wait until the work is completed.
  • Use DAO to retrieve domain objects and check their status

Obviously, all of the above should be performed within one transaction, but, unfortunately, transactions do not apply to new threads (I understand that the rationale for this).

Ideas that came to my mind:

  • Commit transaction # 1 after step (1). Not good, because the state of the database should be discarded after the unit test.
  • Use Isolation.READ_UNCOMMITTED in the job configuration. But this requires two different configurations for testing and for production.
+3
java spring multithreading transactions
source share
3 answers

I think that the easiest solution would be to configure JobLauncher with SyncTaskExecutor during the test execution - in this way the task is executed in the same thread as in the test and shares the transaction.

The configuration of the task executor can be transferred to a separate spring XML configuration file. They have two versions: one with SyncTaskExecutor, which is used during testing, and the other AsyncTaskExecutor, which is used for production launches.

+2
source share

Although this is not the right solution to your question, I found it possible to start a new transaction inside the workflow manually. In some cases, this may be sufficient.

Source: Spring software 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
source share

If you need a separate configuration, I would recommend an isolation policy template in your configuration and get its value from the properties file so that you do not finish working with a diverging set of Spring configurations for testing and prod.

But I agree that using the same uses in politics is best. How extensive is your hardware data, and how bad would it be to have a setUp() step that would blow away and rebuild your data (maybe from a snapshot if it has a lot of data) so you don't have to rely on rollbacks?

+1
source share

All Articles