Using Spring, I am reaching the following scenario.
I have a service that has to be #Transactional because it calls several DAOs. But it also calls other services that are already #Transactional.
Somehow, I will be calling nested #Transactional services.
Will Spring manage well?
#Transactional without any explicit parameters uses propagation = REQUIRED. This means:
If there is no transaction in the current thread, a new transaction will be created
If there is a transaction, it will be used
The 2nd service (the nested one) annotated with #Transactional will be executed in the same transaction as the 1st one (the outer one). You don't need to do anything.
In some cases if you want to explicitly separate the nested call from the outer one you can use propagation = REQUIRES_NEW.
Related
I'm using Spring Boot 1.4 and trying to understand how does Spring Transaction Management works.
Here is my question:
Lets say I have a service with a method A that is annotated with #Transactional(isolation = SERIALIZABLE) and another method B annotated with #Transactional(isolation = READ_COMMITED).
And then let's imagine that some service X calls these two methods A and B sequentially.
My colleague says that transaction level is set per connection in Spring. Which means that if the same connection from the pool is used for these two sequential calls, then isolation level for both transactions A and B = SERIALIZABLE.
However, to me it seems a bit strange. I would expect that these two transactions would have different level of isolations, because all sql databases allow to set isolation level for a given transaction explicitly.
I was trying to read documentation and couldn't find a place where it would be mentioned that transcation level is assigned to connection.
Can someone judge us on this issue?
If there is no transaction started when calling method A() or B() a new transaction is created when calling the method and gets closed when leaving the method. The used connection returns to pool or gets closed.
This thread explains what happens to the connection when transaction gets closed:
Does Spring close connection after committing transaction?
In case there exists a transaction that wraps both methods, there is only one connection used for both methods; and i guess the isolation level is the one defined by the bigger transaction.
Java web
Spring MVC framework
In my service level, I wrote a #Transactional method. In that method, I update some data in database and then read the data from the database later.
What surprises me is that when several requests come, inside the same thread, the data change is visible(which is supposed to be), but the data change is not visible in other thread.
Isn't different threads of one method build as one transaction?
And what should I do if I still want to use transaction and I want the same method called in different threads be in one transaction (the change of the data can be seen by each other)?
From Professional Java for Web Applications by Nicholas S. Williams
Using Threads for Transactions and Entity Managers
The transaction scope 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.
(I paraphrased it a little the above piece)
I think its self explanatory and answers your question. But I would like to add that, 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.
you may want to play with isolation parameter of#Transactional annotation. Spring by default uses.. hm.. DEFAULT which is set by database, so may be different. You can try to use: READ_UNCOMMITTED. More info: http://www.byteslounge.com/tutorials/spring-transaction-isolation-tutorial
Why methods annotated with #PostConstruct or #PreDestroy in singleton session beans with
container managed transactions can have only one of the following transaction attributes:
• REQUIRED
• REQUIRES_NEW
• NOT_SUPPORTED
I guess because #PostConstruct or #PreDestroy annotated methods are methods invoked by the container during bean creation or destruction, so making these methods part of mandatory transaction wouldn't make sense (since there are no business methods called before #PostConstruct). Same applies for SUPPORT type.
You can make the method transactional by itself (so this method becomes atomic) but it can't join other transactions because it is invoked by the container and you have no control over it.
I have read in the book that:
Typically, the container begins a transaction immediately before an enterprise bean method starts. It commits the transaction just before the method exits.
Suppose my stateful EJB has exposed 3 business methods and the client calls these 3 methods sequentially and want wants to run these 3 methods within a single transaction. These methods would be called across multiple requests.
Now the spec says that the transaction is committed just before the method exits. How will I be able to rollback the whole transaction, if my 1st method is successful and 2nd (or 3rd) method fails?
Please note that I don't want to use create my own transaction boundary.
Any help or the pointer in the right direction would be highly appreciated.
You are using a stateful session bean to act as a buffer. And you want a transaction around multiple calls.
From a design perspective, it's OK, if the transaction is started and committed/rollbacked from a single request (from within a single HttpServletRequest for example). In this case you can use a UserTransaction to span the transaction over multiple calls to an EJB. But a UserTransaction is bound to the current thread, so it might be difficult to pass it to the next request.
If you start and commit from different requests, you lose control over the duration of the transaction: Now a client controls the transaction. If that client crashes, the transaction won't be rolled back until the transaction timeout is reached. So the recommendation in this case is to buffer in a HttpSession for example. If all data has been collected, call a (stateless) EJB to persist it.
Create a method in the bean that calls all the other 3 methods. Then they'll be in the same transaction.
I am working on an EJB3 application with mainly stateless session beans (SLSB). They use container managed transactions (CMT).
I want the beans to be aware of the transactions (for logging, etc). I can implement the javax.ejb.SessionSynchronization to do this. I find that I can register a javax.transaction.Synchronization in a default interceptor also to get similar callbacks.
Are there any dis/advantages to using one over the other?
Multiple SLSB of the same type can be involved in the same transaction. As soon as a method exits, the SLSB is returned to a pool for use by the next invocation, so it is not safe for an SLSB instance to be "aware" of a transaction: by the time it is notified, the bean might be in use in another transaction.
As for SFSB, I would say there is no advantage between the two approaches in theory. However, the EJB container might be using Synchronization for various internal tasks, so using SessionSynchronization would allow the EJB container to have more control over the timing of the callbacks with respect to its own operations.
I just tried to use the javax.ejb.SessionSynchronization interface with a stateless session bean and was confused not to get any calls of the three implemented methods. Then I saw this comment in the javax.ejb.SessionSynchronization JavaDoc:
Only a stateful session bean with container-managed transaction demarcation can receive session synchronization notifications. Other bean types must not implement the SessionSynchronization interface or use the session synchronization annotations.
See also this thread for some more background. So my conclusion is that making stateless session beans transaction-aware using CMT can NOT be achieved with javax.ejb.SessionSynchronization.