Multi-threading Spring Transaction - java

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

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.

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.

Related

In java spring hibernate 3.6.3 how to tell a method to wait until lock is aqured and how to retry a failed transaction?

In my spring application I am facing failed to acquire lock issue and transaction is getting failed. It is not even rollbacking the transaction as database is not providing the lock. How to tell a method to wait until the lock is acquired? I am using hibernate and mysql.
First of all, you have to use #Transactional as method/class annotation in the case of spring.
By default, we have the propagation REQUIRED #Transactional(propagation = Propagation.REQUIRED). Spring checks if there is an active transaction, then it creates a new one if nothing existed.
Here you can find the explanation of spring transaction propagations.
First, you have to take a look and analyze what you need there to use.
Please tell us, where do you face with lock issues?
Probably you have to deal with the Isolation levels; We can deal with them at mySql, hibernate or spring level.
Here we need to know where you have configurations for isolation (mySql, hibernate or spring).
You can check if you need to update the lock timeout, using QueryHints.
#QueryHints({#QueryHint(name = "javax.persistence.lock.timeout", value = "3000")})
public Optional<Customer> findById(Long customerId);

Wildfly treating concurrency management as transactional

I had a class that looked like this:
#Singleton
#ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
#Lock(LockType.WRITE)
#AccessTimeout(value = 20, unit = TimeUnit.MINUTES)
public class MyClass{
public void someLongRunningQuery(){
}
}
However, this would fail with:
org.jboss.resteasy.spi.UnhandledException: javax.ejb.EJBTransactionRolledbackException: Transaction rolled back
I was able to resolve this by adding this annotation.
#TransactionTimeout(value = 20, unit = TimeUnit.MINUTES)
My question is - why is jboss treating this method as a transaction? My understanding is the concurrency management and transaction management are different things.
Transaction timeout handling is not defined in EJB spec and JBoss uses a separate transaction management module to do that. Your example points at a REST access to your singleton - is the Singleton also a REST endpoint or is it invoked from some REST endpoint bean? Just a couple of ideas:
If you have a REST endpoint that injects your singleton and invokes the long running op, isn't it by any chance a #Stateless bean? EJB beans are transaction enabled by default, therefore if a client(REST endpoint) initiates a transaction(it does by default - #TransactionAttribute(REQUIRED)), your singleton will also participate in the same transaction, but because its invocation takes longer than the default transaction timeout value(300s) it causes transaction rollback. If you do not need a transaction on the rest layer, try disabling it with #TransactionAttribute(NOT_SUPPORTED)
If you invoke this long running op from REST layer, wouldn't it be better to use #Asynchronous and return some kind of request/job handle to the client, so that it can query the status of the operation instead of waiting and blocking while it finishes? Keep in mind that EJBs are pooled resources, therefore invoking this long op multiple times can drain your pool and cause acquisition timeouts.

declarative transaction vs programmatic transaction

If we go with programmatic transaction, we write
Session session=sessiongFactory.openSession();
Transaction tx=session.buildTransaction();
And for a session we can build as many transaction we want.
So, We have first session object than we get Transaction Object.
While in Declarative Transaction,If we declarative #Transaction annotation at service level.
"When this Service Method will be called,Transaction will be Open" so here there is not any inforamtion about Session.
Then in Dao we write
Session session=sessiongFactory.getCurrentSession();
Here we have first Transation then Session,
Can any one please help me in understanding ,How spring manages this Declarative Transaction.
According to documentation method sessiongFactory.getCurrentSession() obtains the current session, and"current session" means controlled by the CurrentSessionContext impl configured for use.
Documentation also provides this explanation for backwards compatibility: if a CurrentSessionContext is not configured but a JTA TransactionManagerLookup is configured, this will default to the JTASessionContext impl.
JTASessionContext implementation will generate Sessions as needed provided a JTA transaction is in effect. If a session is not already associated with the current JTA transaction at the time currentSession() is called, a new session will be opened and it will be associated with that JTA transaction.
With Spring declarative transaction management you can apply #Transactional at both method & class level.
It is enabled via AOP proxies. The combination of AOP with transactional metadata yields an AOP proxy that uses a TransactionInterceptor in conjunction with an appropriate PlatformTransactionManager implementation to drive transactions around method invocations.
Conceptually, calling a method on a transactional proxy looks like this…
When using proxies, you should apply the #Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the #Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings.
All transactions are associated with the session. Transactions are initiated on the service layer but they have to be associated with a session to be committed. First transaction completes then session is closed. A session can also span several transactions. If you are using hibernate, spring uses hibernate managed transaction manager which is responsible for associating transactions with hibernate session.
Spring transaction management abstract the transaction handling and decouples the transaction demarcation logic (e.g. #Transactional) from the actual transaction manager (e.g. RESOURCE_LOCAL, JTA).
The problem with programmatic transaction is that you tie your application code to the transaction management logic. On the other hand, Spring allows you to switch from JpaTransactionManager to JtaTransactionManager with just some configuration (no need to change the application code).
Spring only creates a transaction context that's used by the inner TransactionInterceptor to execute the actual transaction management hooks.
For RESOURCE_LOCAL, transactions are handled through the JDBC Connection commit() and rollback() methods.
For JTA, transactions are handled through the JTA UserTransaction commit() and rollback() methods.
Everything is explained in the docs. You may also want to take a look at Spring integration with ORM.
Basically, Spring creates a proxy which intercepts the transactional methods invocation and starts the transaction before delegating the call to the target method, and ends the transaction when the target method returns.

Will Spring estabilish connection to DB, when I use transacional bean in non-transacional?

Good day, guys!
If I have non-transactional bean(BannerSizeServiceUntransact), which uses transactional bean(bannerSizeService), will Spring estabilish connection to DB, when I use non-transacional bean?
(I have many refused connections to PostgreSQL in log. I belive my logic does;t create new connection on each request, but may be I wrong.)
#Repository
public class BannerSizeServiceUntransactImpl implements BannerSizeServiceUntransact {
#Resource
BannerSizeService bannerSizeService;
public List<BannerSizeVO> sizesByType(String type) throws BannerServiceException{
return bannerSizeService.sizesByType(type);
} }
#Repository
#Transactional
public class BannerSizeServiceImpl implements BannerSizeService {
....
}
Yes, Spring will establish a database connection even when you're using beans that aren't marked #Transactional, so that's not the cause of your refused connections.
What's going to happen in this scenario is that when you invoke the call to bannerSizeService.sizesByType(type), Spring will start a new transaction, and when control returns to BannerSizeServiceUntransact.sizesByType(), it will end. So if BannerSizeServiceUntransact.sizesByType() did other database calls before or after the call to bannerSizeService.sizesByType(type), those calls would happen in separate transactions, one per DB call. (Not annotating a Service as #Transactional doesn't mean that transactions aren't used, just that they only span a single database call.)
Also note that if the method that calls BannerSizeServiceUntransact.sizesByType() was marked #Transactional, then the transaction started there will carry over all of the code you've shown here, because that transaction will start when that higher-up method is called and will end when it ends, and all of the code here will have executed while it was in effect. Not annotating something as #Transactional doesn't forbid its participation in an existing transaction, it just doesn't require the initiation of a new one.
Also, keep in mind that #Transactional controls transactions. Spring might end up making a new connection for each transaction it opens, or using only one and reusing it for each transaction, or rotating through a pool of connections (resulting in more than one but fewer than N connections for N transactions). It's guaranteed that if Spring talks to the database, there will be a connection in use, but you can't guarantee how many will be used over N calls simply by your #Transactional annotations. (Though of course you can set settings in your Spring config that might impact the number used, e.g. specifying a connection pool with a max size of 1.)

manual commits with #Transactional attribute

I use spring+hibernate template to process entities. There is rather big amount of entities to be loaded all at once, so I retrieve an iterator from hibernate template.
Every entity should be processed as a single unit of work. I tried to put entity processing in a separate transaction (propagation = REQUIRED_NEW). However I ended with exception stating that proxy is bounded to two sessions. This is due to suspended transaction used for iterator lazy loading. I am using the same bean for lazy loading and for processing entities. (May be it should be refactored into two separate daos: one for lazy loading and one for processing?)
Then I tried to use single transaction that is committed after each entity is processed. Much better here, there are no exceptions during entity processing, but after processing is finished and method returns, exception is thrown from spring transaction managing code.
#Transactional
public void processManyManyEntities() {
org.hibernate.Sesstion hibernateSession = myDao.getHibernateTemplate().getSessionFactory().getCurrentSession();
Iterator<Entity> entities = myDao.findEntitesForProcessing();
while (entities.hasNext()) {
Entity entity = entities.next();
hibernateSession.beginTransaction();
anotherBean.processSingleEntity(entity);
hibernateSession.getTransaction().commit();
}
}
processSingleEntity is a method in another bean annotated with #Transactional, so there is one transaction for all entities. I checked what transaction causes an exception: it is the very first transaction returned from hibernateSession.beginTransaction(), so it just not updated in transaction manager.
There are several questions:
is it possible to avoid session bind exception without refactoring the dao? that is not relevant question as problem is with Session and hibernate not with dao
is it possible to update transaction in the transaction manager? solved
is it possible to use the same transaction (for anotherBean.processSingleEntity(entity);) without #Transactional annotation on processManyManyEntities?
I would prefer to remove the #Transactional annotation on "processManyManyEntities()", and, to eagerly load all data from "findEntitesForProcessing".
If your want each entity of data to be transactional in "processSingleEntity", the #Transactinoal on "processSingleEntity" is fine. You don't have to annotate the #Transactional on "processManyManyEntities()". But in case of lazy loading, eager loading is a necessary mean to prevent the source data from loading in another session, say, in "processSingleEntity".
Since the transaction for each entity of data, the transactional boundary in loading of source data is not the case of your transaction. Don't let the "lazy loading" to complicate your intent of transaction for modification of data.
That is possible to update transaction in transaction manager. All you need to do is get SessionHolder instance from TransactionSynchronizationManager.getResource(sessionFactory) and set transaction in the session holder to the current. That makes possible to commit transaction whenever it is necessary and allows transaction to be committed by spring transaction manager after method return.

Categories