Intercepting transaction multiple times - spring

How bad is it intercepting transaction multiple times?
For example one service method marked #Transactional calls another service method which also is marked with #Transactional annotation and so on? Which problems may it cause?

There is the propagation attribute at the #Transactional annotation. It is responsible for setting the expected behavior when a (second) method with #Transactional is invoked.
#See Java Doc: Transactional.propagation
#See Java Doc: Propagation

Related

Spring non-transactional nested method inside #transactional is the same as #transactional propagation = support

i) Are there any difference, 1) if I call a non-transactional method from inside #transactional AND 2) call call a #transactional with propagation level = support from the same #transactional method?
ii) Are there any difference if answer for the question i) if it's the same bean or different?
Thanks
i) Are there any difference,
1) if I call a non-transactional method from inside #transactional AND
If you call a method within a transaction, without any settings, the transaction will span to the calling method.
2) call call a #transactional with propagation level = support from the same #transactional method?
Propagation.SUPPORTS annotated method will be executed in the current transaction, just like if you call a non-transactional method.
The only different between setting #Transactional(propagation = Propagation.SUPPORTS) and not setting #Transactional is noted in javadoc:
Note: For transaction managers with transaction synchronization, PROPAGATION_SUPPORTS is slightly different from no transaction at all, as it defines a transaction scope that synchronization will apply for. As a consequence, the same resources (JDBC Connection, Hibernate Session, etc) will be shared for the entire specified scope. Note that this depends on the actual synchronization configuration of the transaction manager.
ii) Are there any difference if answer for the question i) if it's the same bean or different?
Spring #Transactional annotation default using AOP proxy.
When you calling methodB from methodA within the same class, the AOP proxy will not be activated for the methodB (i.e #Transactional annotation in methodB is completely ignored).
When you calling from different class, then the behavior is same as i)

Spring disable transactions for a single class method

In my Spring application, I have a class annotated with org.springframework.transaction.annotation.Transactional annotation.
Is it possible to discard transactions for a specific single method of this class without removing #Transactional from class level declarations? If so, please show an example
According to Transactional documentation:
public #interface Transactional
Describes a transaction attribute on an individual method or on a class.
So additionally to the class-level annotation just define the correct attribute at your method to disable the default transaction handling.
example:
#Transactional(propagation=Propagation.NEVER)
public long notInTransaction(AnythingData anythingData) throws Exception {
//JDBC code...
}
Will throw an exception if this method is called inside an active transaction. Whereas Propagation.NOT_SUPPORTED will "suspend" the current transaction and make sure that the method is called non transactional.

Where can I use #Transactional

Can someone explain me why this will work:
#Transactional
#Test
public void test() {
save();
}
public void save() {
Scenario scenar = new Scenario();
sessionFactory.getCurrentSession().save(scenar);
}
And this won't, because it won't find a transaction:
#Test
public void test() {
save();
}
#Transactional
public void save() {
Scenario scenar = new Scenario();
sessionFactory.getCurrentSession().save(scenar);
}
Thank you!
Spring #Transactional annotation works using Spring AOP. This means, that when a bean that contains a method with that annotation is injected as a dependency for a different bean, it gets wrapped in a proxy. This proxy has the same interface as the bean, but performs additional actions before a method is invoked (wrapping it in a transaction in this case). You can think of it as a sort of a decorator. You can even see the proxy being invoked when you debug your application.
Now, when the method that you annotate with #Transactional is called from the same class, there is no (at least, no easy) way to inject the proxy. There just isn't a way to replace the object referenced by the "this" keyword in Java.
More reading on Spring AOP proxies.
As you have a method annotated as #Test I assume this is part of a Junit Test class.
Spring developpers know that test methods usually do not implement interfaces, and as such cannot support JDK proxying. So they specially support #Transactional annotation on a #Test method. The doc says :
Enabling and disabling transactions
Annotating a test method with #Transactional causes the test to be run within a transaction that will, by default, be automatically rolled back after completion of the test. If a test class is annotated with #Transactional, each test method within that class hierarchy will be run within a transaction. Test methods that are not annotated with #Transactional (at the class or method level) will not be run within a transaction. Furthermore, tests that are annotated with #Transactional but have the propagation type set to NOT_SUPPORTED will not be run within a transaction.

Transactional annotation on whole class + excluding a single method

I have a class with #Transactional annotation (instead of marking it for all of its method).
Although i have a single method inside that class that shouldn't be annotated as #Transactional.
My question is is there an annotation i can put in this method to mark it as "non-transactional"? or should i start marking each single method in this class as "transactional" excluding this method (a lot of work)
thanks.
There are different transaction propagation strategies to use. These exist in the enum Propagation. The ones you might want to use are
/**
* Execute non-transactionally, suspend the current transaction if one exists.
* Analogous to EJB transaction attribute of the same name.
* <p>Note: Actual transaction suspension will not work on out-of-the-box
* on all transaction managers. This in particular applies to JtaTransactionManager,
* which requires the {#code javax.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard J2EE).
* #see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
/**
* Execute non-transactionally, throw an exception if a transaction exists.
* Analogous to EJB transaction attribute of the same name.
*/
NEVER(TransactionDefinition.PROPAGATION_NEVER), // maybe not this one
So annotate the method inside your class with either of these.
#Transactional
public class MyTransactionalClass {
#Transactional(propagation = Propagation.NOT_SUPPORTED)
public void nonTransactionalMethod() {...}
}
You can find all the propagation strategies here.
Sorry to answer a six year old question, but I noticed the accepted answer doesn't actually answer the question. The question was how to have a method behave as though it was not annotated with #Transactional at all. Such a method will take part in a transaction if there is one, or execute non-transactionally if there is not. It will not suspend an existing transaction, or refuse to execute if there is one, one of which would be the result of the accepted answer.
The propagation to use is Propagation.SUPPORTS (in other words annotate the method with #Transactional(propagation = SUPPORTS). This will take part in the transaction if there is one, or execute non-transactionally if not, just like a non-annotated method would.
Not that according to the Javadoc it is not exactly the same as having no #Transactional annotation at all. It says:
Support a current transaction, execute non-transactionally if none exists. Analogous to EJB transaction attribute of the same name.
Note: For transaction managers with transaction synchronization, SUPPORTS is slightly different from no transaction at all, as it defines a transaction scope that synchronization will apply for. As a consequence, the same resources (JDBC Connection, Hibernate Session, etc) will be shared for the entire specified scope. Note that this depends on the actual synchronization configuration of the transaction manager.
The only way to have the method behave exacty as if it was not annotated with #Transactional at all is to do as OP suggests: don't annotate the class, but annotate all the other methods, but for most uses that will not be necessary and using Propagation.SUPPORTS will suffice.

#Transactional Annotation + for a data insertion in a loop

I am using Spring 3, JPA + Hibernate for a CMS application. In that application I have a service class method which is annotated with #Transactional Annotation with rollBack property. Inside that method I am inserting data (ie entity classes) to a table using a loop. For each iteration of the loop entity classes has to be saved to the database. But it is not happening. The commit only happens when the execution of the loop has completed and exits from the method. Then it commits and saves all at once. But I need to read data once it gets inserted into the database before committing in this case. I tried with the ISOLATION LEVEL to read uncommitted but it didn't supported since I am using the default JPADialect. Also tried to add the hibernate implementation of jpaDialect but still it didn't worked. Please help with a workaround for this problem. One more thing, is there any way using propagation required method.
You are right, this is what I stands for in acid. Because the transactions are working in isolation, other transactions cannot see them before they are committed. But playing with isolation levels is a bad practice. I would rather advice you to run each and every iteration in a separate transaction with start and commit inside.
This is a bit tricky in Spring, but here is an example:
public void batch() {
for(...) {
insert(...)
}
}
//necessarily in a different class!
#Transactional
public void insert() {
}
Note that batch() is not annotated with #Transactional and insert() has to be in a different class (Spring service). Too long to comment, but that's life. If you don't like it, you can use TransactionTemplate manually.
remove the transactional annoation on the the method with loop.
In the loop call a separate method to perform the save, make that method transactional
You either need to go with programmatic transactions (Spring's TransactionTemplate or PlatformTransactionManager are the classes to look at, see Spring Doc for programmatic transactions, or you can call another transactional method from within your loop where the transaction is marked with Propagation.REQUIRES_NEW, meaning each call of that method is executed in its own transaction, see here. I think that the second approach requires you to define the REQUIRES_NEW method on a different Spring bean because of the AOP-Proxy. You can also omit the REQUIRES_NEW if the loop is not executed within a transaction.

Resources