14

Assume that we go inside a method and start a transaction in main thread. In this method, there are some async methods so we created 2 more threads inside this method;

                 Thread 1 --> SubMethod1 --> Saving (t=1)
                   ^
                   |
MainThread --> MainMethod --> Saving (t=3)
                   |
                   v   
                 Thread 2 --> SubMethod2 --> Exception while saving (t=2).

Since thread 2 gets an exception, I want to rollback all transactions done by other threads. However, although transactions owned by main thread an Thread 2 can be roll-backed, I cannot roll-back thread 1 work. I am using Spring/Hibernate, so do you have any idea to manage this and how to apply?

Thanks

Can Cinar
  • 401
  • 1
  • 8
  • 18
  • 2
    Don't use threads. Transactions are thread bound and you have multiple transactions. You cannot rollback a committed transaction. The only "solution" would be to manually undo the work (deleting records, restoring old state etc.). – M. Deinum Sep 05 '18 at 05:52
  • Answered here: https://stackoverflow.com/a/30091149/3971900 – Aníbal Nov 11 '22 at 21:51

2 Answers2

13

From Professional Java for Web Applications by Nicholas S. Williams

The transaction scope in Spring is limited to the thread the transaction begins in. The transaction manager then links the transaction to managed resources used in the same thread during the life of the transaction. When using the Java Persistence API, the resource you work with is the EntityManager. It is the functional equivalent of Hibernate ORM’s Session and JDBC’s Connection. Normally, you would obtain an EntityManager from the EntityManagerFactory before beginning a transaction and performing JPA actions. However, this does not work with the Spring Framework model of managing transactions on your behalf. The solution to this problem is the org.springframework.orm.jpa.support.SharedEntityManagerBean. When you configure JPA in Spring Framework, it creates a SharedEntityManagerBean that proxies the EntityManager interface. This proxy is then injected into your JPA repositories. When an EntityManager method is invoked on this proxy instance, the following happens in the background:

➤➤ If the current thread already has a real EntityManager with an active transaction, it delegates the call to the method on that EntityManager.

➤➤ Otherwise, Spring Framework obtains a new EntityManager from the EntityManagerFactory, starts a transaction, and binds both to the current thread. It then delegates the call to the method on that EntityManager. When the transaction is either committed or rolled back, Spring unbinds the transaction and the EntityManager from the thread and then closes the EntityManager. Future @Transactional actions on the same thread (even within the same request) start the process over again, obtaining a new EntityManager from the factory and beginning a new transaction. This way, no two threads use an EntityManager at the same time, and a given thread has only one transaction and one EntityManager active at any given time.

If you were not to use Spring MVC then you would have gotten the session using SessionFactory in Hibernate. Hibernate Sessions represent the life of a transaction from start to finish. Depending on how your application is architected, that might be less than a second or several minutes; and in a web application, it could be one of several transactions in a request, a transaction lasting an entire request, or a transaction spanning multiple requests. A Session, which is not thread-safe and must be used only in one thread at a time, is responsible for managing the state of entities.

Faraz
  • 6,025
  • 5
  • 31
  • 88
  • So let's say an endpoint needs to `DELETE FROM` 3 tables, and then `INSERT INTO` those same 3 tables. The insertions need `SELECT` from 2 other unrelated tables. There would be no way to multithread this endpoint by issuing all the `DELETE`s together (each table request executed in a separate thread) along with the `SELECT`s (again: one thread per DB request), followed by a blocking call that awaits all the results to finally issue `INSERT`s in their own thread? (All this for a total of 5 threads handling all 8 requests, instead of one thread doing this whole work sequentially.) – payne Dec 07 '21 at 16:40
  • @payne I am not in a position to answer this question at the moment. – Faraz Dec 08 '21 at 01:04
2

This post https://dzone.com/articles/spring-transaction-management-over-multiple-thread-1 appears to cover the issue quite well and mentions a project that is doing something similar.

Mr Chow
  • 365
  • 6
  • 10