I am trying to understand the propagation attribute of #Transactional annotation in Spring Data JPA. I have read enough theory. But I do not understand(nor can I find anywhere on internet) the real-life scenario where I need to use the PROPAGATION_REQUIRED in place of PROPAGATION_REQUIRES_NEW. I understand the theory that PROPAGATION_REQUIRED can utilize the existing transaction and PROPAGATION_REQUIRES_NEW will start a new transaction each time. But I could not understand two things -
How does it matter to me as a programmer? or in which used cases one is preferred over other?
Is the "TRANSACTION" we are talking about is a spring transaction or a database transaction
In Spring, if a method that is annotated with #Transactional calls another method annotated with #Transactional, the transaction is started at the beginning of the first method and commited after the second method is finished.
Requiring a new transaction can be helpful, if you have a sequence of methods that are transactional but you want to commit a transaction half way through the sequence.
Or maybe you have a method that should always open it's own transaction and you want to make sure it does so, even if it is called by another transactional method.
Related
I have inherited a system that uses Spring MVC and Hibernate that stores into a DB2 database. Recently it started having what looks like a deadlock problem reported by DB2 so I've been working on debugging it. I'm not a Spring or Hibernate expert but I know some of both.
The code is structured like this:
controller -> service -> one or more DAO classes that performs the updates
In the situation where the problem occurs the controller calls a service method annotated with #Transactional and #Override. The service goes to a DAO class annotated with #Repository and calls multiple methods annotated with #Transactional and #Override. That is the structure of code.
One controller calls one service method. The service method calls multiple DAO methods. Most of the DAO methods are marked #Transactional and #Override. A few have REQUIRES_NEW in the #Transactional. Also in each DAO method the Session is gotten by SessionFactory.getCurrentSession().
First question: with this approach where does the transaction start and where is the ultimate commit? And the rollback? None of this is explicitly coded.
The deadlock comes when one of the methods updates a record and then a subsequent method deletes that same record. If you are wondering why anyone wants to do this the update adds the user id of the person wanting to delete the information in the record so that it can be saved by a stored process to another table. Then the second method call deletes the record.
The original coder tried adding REQUIRES_NEW to the #Transactional thinking a new transaction would ensure the update would happen. But the deadlock still happens at irregular intervals.
I tried changing the update to a native SQL call but Hibernate won't let me start another transaction since one is already open.
Anyone have any guidance here?
The transaction starts when a method (which class or the method itself firstly annotated with #Transactional in the call chain) called from outside (it must call from outside of the class, because the annotation "creates" a proxy). Any other annotated class/methods in the chain with default propagation level will join to that transaction. When call a method with transactional marked as REQUIRES_NEW, the parent transaction will be suspended (if exists) and the new transaction starts. Note that if you call annotated method from other method in the same class, then it wont go throught the proxy, so it same as you delete the annotation. The commit happened right after the method who start the transaction return. Same as rollback, it will after exception is thrown. Deadlock can come from different places, it is hard to find out, even if you have code. It can for example come from update and stored procedure try to lock some rows and cyclic waiting happend etc...
I have a naive image, what happen in the background.
There are two class ui and service. The service is annotated as #Transactional.
Spring create the proxy, and all calls come from outside go through it. Before the real method will be called, it start the transaction, after that it will commit.
I have a web application that uses Spring NamedJDBCTemplate, and all the calls to database are select statements.
In this case should i use #Transactional in my service class that calls the DAO class that inturn fires select statements to DB.
According to Transaction statergies listing 10 suggests to not use #Transactional for reads. Will i be bringing an overhead by using #Transactional and also i dont want to miss the AOP advises that i can bring in for #Transactional in future.
Yes, you should always access the database from inside a transaction. Not doing it will in fact create a transaction for every select statements.
Transactions aren't just useful for atomicity of updates. They also provide isolation guarantees. For example, (depending on the isolation level) reading the same row twice in a single transaction can return you the same data, and thus make sure you don't have incoherences in the read data. Doing it with multiple transactions won't provide any such guarantee.
I think the best way is to use #Transactional and set it as Supported not Required for such service
in this way if your service call outside a transaction it will not start a Transaction and if it calls from other service that is Transactional and already start a transaction it will participate in that transaction.
for example think that one service required to call two services in first one some data will inserted or updated and other one is just a select that return those data if these two service don't participate in single transaction the second service will not return data because the transaction start in calling service not committed yet .
I'm having a difficult time understanding Spring Transactions. First off, I am trying to use as little of Spring as possible. Basically, I want to use #Transactional and some of its injection capabilities with JPA/Hibernate. My transactional usage is in my service layer. I try to keep them out of test cases. I use CTW and am spring-configured. I have component scan on the root of my packages right now. I also am using Java configuration for my datasource, JpaTransactionManager, and EntityManagerFactory. My configuration for the JpaTransactionFactory uses:
AnnotationTransactionAspect.aspectOf().setTransactionManager( txnMgr );
I do not use #EnableTransactionManagement.
Unfortunately, I'm having a hard time understanding the rules for #Transactional and can't find an easy page that describes them simply. Especially with regards to Session usage. For example, what if I want to use #Transactional on a class that does not have a default no-arg constructor?
The weirdest problem I'm having is that in some of the POJO service classes Transacitonal works great while in others I can see the transactions being created but operations ultimately fall saying that there is "no session or the session has been closed". I apologize for not having code to reproduce this, I can't get it down to a small set. This is why I am looking for the best resources so I can figure it out myself.
For example, I can have a method that gets a lazily fetched collection of children, iterates through it and puts it into a Set and returns that set. In one class it will work fine while in another class also marked with #Transactional it will fail while trying to iterate through the PersistentSet saying that there is no session (even though there IS a transaction).
Maybe this is because I create both of these service objects in a test case and the first one is somehow hijacking the session?
By the way, I have read through the spring source transaction documents. I'm looking for a clear set of rules and tips for debugging issues like this. Thanks.
Are you sure you loaded your parent entity in the scope of the very transaction where you try to load the lazy children? If it was passed in as parameter for example (that is, loaded from outside your #Transactional method) then it might not be bound to a persistence context anymore...
Note that when no #Transactional context is given, any database-related action may have a short tx to be created, then immediately closed - disabling subsequent lazy-loading calls. It depends on your persistence context and auto-commit configurations.
To put it simply, the behaviour with no transactional context being sometimes unexpected, the ground rule is to always have one. If you access your database, then you give yourself a well-defined tx - period. With spring-tx, it means all your #Repository's and #Services are #Transactional. This way you should avoid most of tx-related issues.
I use JTATransactionManager to manage Transactions. One piece of code that I want to wrap with Spring's #Transactional annotation has 2 database calls - one using Hibernate SessionFactory and another a plain JDBC. Both use the same dataSource. Hence, I expect both to be bound by the same Transaction.
But it does not look like one Transaction is used. Instead each opens its own Transaction. What could be the reason for this. ? How do I make sure to use a single Transaction to bind both these operations. ?
I can provide configuration and code if needed.
Make sure in both of your database calls, you use propagation as Propagation.NESTED as
#Transactional(propagation=Propagation.NESTED)
and in the wrapper method, you mention Propagation.REQUIRED orPropagation.REQUIRED_NEW` as
#Transactional(propagation=Propagation.REQUIRED)
or
#Transactional(propagation=Propagation.REQUIRED_NEW)
By doing this, you mention that both DB calls will inherit the transaction boundary of the wrapper method.
if some one can explain what this annotation do and when exactly we use it :
#Transactional(propagation=Propagation.REQUIRED)
Thanks
If you need a laymans explanation of the use beyond that provided in the Spring Docs
Consider this code...
class Service {
#Transactional(propagation=Propagation.REQUIRED)
public void doSomething() {
// access a database using a DAO
}
}
When doSomething() is called it knows it has to start a Transaction on the database before executing. If the caller of this method has already started a Transaction then this method will use that same physical Transaction on the current database connection.
This #Transactional annotation provides a means of telling your code when it executes that it must have a Transaction. It will not run without one, so you can make this assumption in your code that you wont be left with incomplete data in your database, or have to clean something up if an exception occurs.
Transaction management is a fairly complicated subject so hopefully this simplified answer is helpful
When the propagation setting is PROPAGATION_REQUIRED, a logical transaction scope is created for each method upon which the setting is applied. Each such logical transaction scope can determine rollback-only status individually, with an outer transaction scope being logically independent from the inner transaction scope. Of course, in case of standard PROPAGATION_REQUIRED behavior, all these scopes will be mapped to the same physical transaction. So a rollback-only marker set in the inner transaction scope does affect the outer transaction's chance to actually commit (as you would expect it to).
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/transaction.html
In Spring applications, if you enable annotation based transaction support using <tx:annotation-driven/> and annotate any class/method with #Transactional(propagation=Propagation.REQUIRED) then Spring framework will start a transaction and executes the method and commits the transaction. If any RuntimeException occurred then the transaction will be rolled back.
Actually propagation=Propagation.REQUIRED is default propagation level, you don't need to explicitly mentioned it.
For further info : http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/transaction.html#transaction-declarative-annotations
To understand the various transactional settings and behaviours adopted for Transaction management, such as REQUIRED, ISOLATION etc. you'll have to understand the basics of transaction management itself.
Read Trasaction management for more on explanation.