I am basically trying to understand transaction management in spring. When we use #Transactional annotation with a method, does spring call all it's sub-functions also within the same transaction?
In a scenario where you have used #Transactional and your sub-function throws a DB Exception, if you have not explicitly mentioned rollback, what happens? (If you have mentioned rollback in sub-function, I believe the entire transaction is reverted, please correct me if I am wrong). How is transaction management handled without any annotations (does spring create a new transaction for each DB call?) And finally, are all these behaviours same for
javax.transaction.Transactional
and for
org.springframework.transaction.annotation.Transactional
?
I have been reading resources on the same, but am confused about these base concepts. I am trying to clarify them else I might learn them wrong. Could somebody please help?
Thank you in advance.
Related
Hi I have a distributed transactions and I have to manage them somehow
Also in spring ecosystem ChainedTransactionManager can do that on the other hand in spring document Atomikos can be used for distributed transactions
https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/boot-features-jta.html
Which one I should use?I prefer to stay in spring librarys but Atomikos is much more than spring transaction manager?If someone use them both,Can compare pros and cons
Using Atomikos is a better overall solution. The ChainedTransactionManager is something you can use in some cases. The assumption it makes are stated in the javadocs:
PlatformTransactionManager implementation that orchestrates transaction creation, commits and rollbacks to a list of delegates. Using this implementation assumes that errors causing a transaction rollback will usually happen before the transaction completion or during the commit of the most inner PlatformTransactionManager.
The configured instances will start transactions in the order given and commit/rollback in reverse order, which means the PlatformTransactionManager most likely to break the transaction should be the last in the list configured. A PlatformTransactionManager throwing an exception during commit will automatically cause the remaining transaction managers to roll back instead of committing.
The chance of committing one transaction and the other one failing still remains with ChainedTransactionManager.
Using Atomikos is a real distributed transaction all or nothing on both databases. But this also has some consequences that can affect the support of the application, for example when the TX is fully commited on one DB and prepared on the other, and at that point the application crashes. You'll need to ensure that your application can recover from this scenario. Usually the TX would be fully commited on the second DB when the app is restarted, but that might not happen.
So which one is the right one? It depends.
I am working on an application written in Spring-Boot and JPA, the application has started from scratch. So I am thinking of introducing transaction management in it. There is entity and service layer in the application. Right now what I am thinking is that to go with Spring declarative transaction management. So, I have decided to put the #Transaction annotation on the top of the service layer itself as shown below, please advise is there any best approach to do the same also please make a note that I am using spring-boot-starter-data-jpa dependency itself
#Transactional
public class UserService {
}
Question is a bit too general, but your way of thinking is one of the standard and acceptable ways to work with declarative transaction management. I usually though do it per service method. This way you can specify if transaction is read only and some other parameters per particular service method which I think is more flexible.
It's not quite clear what your question is; do you just want someone to tell you that your approach is valid?
When you design a Spring application with a layered architecture, it is common to have the transaction boundaries on the service layer. The service layer then uses Spring Data repositories (which are in the data access layer). Your approach, where you use #Transaction annotations on the service layer, is a common way of doing this. So you are on the right track.
I've read that the new way of creating Hibernate DAO is using Hibernate contextual sessions. The main reason being to avoid the Spring based HibernateTemplate/HiberateDaoSupport and thus Spring-Free DAO.
When I searched what to do with Exception translation? It's written everywhere that I should use #Repository! #Repository does need import and creates dependencies in my code. Am I right?
Aren't annotations considered dependency? If they are, is there anyway I can have that using XML? Or should I use the old HibernateDaoSupport way, since I'm going to have my code coupled with Spring anyway?
Update
Found a similar question: "integrate hibernate with spring without spring dependency in dao" but:
The first paragraph of the answer that #pap has given does not specify any clear XML alternative for #Repository.
The insight offered in the rest of that answer is plausible, yet my question remains unanswered that if decoupling is not much of a concern, why did Spring try proposing the new approach to Hibernate DAO?
P.S. This is not a criticism. It's rather an attempt to learn the proper way of thinking about this topic (i.e. the dependency).
The point of Spring exception translation in the first place is to break a dependency on Hibernate by creating a dependency on Spring. Regardless of the annotation, Spring exception translation catches a Hibernate exception and turns it into a Spring exception. By putting catch statements in your code tied to the Spring exception you are coupling your code to Spring far more directly than by adding any #Repository annotations. If you don't want to depend on Spring then simply use the Hibernate exceptions directly. Basically, there are two approaches:
Use Hibernate for exceptions and contextual sessions (no coupling to Spring). In this case, simply don't use Spring exception translation at all.
Use Spring for exceptions and session handling (looser coupling to Hibernate, additional coupling to Spring).
I need to use two different dataSources/transactionManagers for different methods. The concept with #Transaction(value="txManagerABC") and a defined qualifier in the applicationContext for the transaction manager is perfect. (As seen in Spring multiple #Transactional datasources)
Unfortunately I need to do the same thing with Spring 2.5. Does anyone have an idea how to solve this?
I believe the recommended way would be to fall back to XML transaction aspect configuration. If you really want annotations, you could probably make some modifications to the #Transactional annotation and surrounding infrastructure to make it work. Or you could update to Spring 3. There is very little to no compatibility issue between 2.5 and 3.
The problem is, the Transactional annotation does not let you specify a transaction manager , and one transaction manager can only manage one DataSource. but There's a way to do so by using JTA and JTOM , see how you can do it here
In my spring configuration I have two transaction managers defined for two different databases. Is there a way in spring to check on runtime whether given method is running inside transaction and secondly (and more importantly) from which transaction manager was this transaction created.
You can use the TransactionSynchronizationManager. It has a number of methods to tell you whether the transaction is active and what's its name. You can get the resource map (getResourceMap()) and verify what's inside.
Everything in that class is ThreadLocal, so it will give you information about the current transaction.
However, the documentation says:
To be used by resource management code but not by typical application code.
It is not clear why you would need that information. Spring uses declarative transactions so that the actual code does not have to know about (and handle) transactional behaviour. If you need to differentiate between transaction managers in the code, then something might be wrong.