Using the default PROPAGATION_REQUIRED with #Transactional behaviour - spring

I know that when you put say #Transactional on a class each method inside will be executed as part of one single transaction if you call them one after the other in sequence because the default spring transactional behaviour is PROPAGATION_REQUIRED. See docs http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#tx-propagation . So assume I have a class like:
#Service
#Transactional
public class ActorServiceImpl implements ActorService
{
public void method1(){}
public void method2(){}
}
However, I want to know what happens if method1 throws an exception and the transaction has to be rolled back then I guess method2 will never be executed because the transaction has already committed due to the exception in method1?

Related

How to declare `#Transactional` in a Spring Boot service so exception is thrown "immediately"?

Say I have the following spring beans in a spring boot app. My intent is to make createFoo() transactional so:
When barService.bar() throws exceptions, the persist gets rolled back.
When the persist throws exception, the exception propagates up to the caller "immediately" so barService.bar() is NOT called.
#Service
public class FooService
{
#Autowired
private FooRepository fooRepository;
#Autowired
private BarService barService;
#Transactional
public void createFoo(Foo foo) {
fooRepository.save(foo);
// expect to not execute when the above line throws exceptions
barService.bar();
}
}
#Service
public class BarService {
public void bar() {
}
}
So far the 1st requirement works, however the 2nd doesn't. When the persist throws exception, barService.bar() is AlWAYS called.
If I remove #Transactional, 2nd requirement works, the 1st doesn't.
I also tried all Propagation types, none of them work as I expected. For example, if I use #Transactional(MANDATORY), I get the following error:
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
Without #Transactional, each call to a repo method is a standalone transaction and it will be flushed immediately. That's why your 2nd requirement worked without #Transactional.
When you add #Transactional, the whole createFoo() becomes one single unit of transaction. Hence, the changes you make when calling save() will only be flushed when createFoo() completes its execution. That's why your 1st requirement worked with #Transactional.
To achieve what you want, keep #Transactional and call saveAndFlush() instead of save().

Spring single Request with multiple transaction does earlier transactional entity becomes detouch

In spring framework project > In a single Request I called foo() method which is #Transactional and next called bar() method which is also #Transactional.
My question is do the entities loaded in foo() are still available in the persistance context. My point is, the Transactional is over but persistance context is exist science the hibernate session is still alive science the request is not yet completed.
Let's say we have bean FooBean:
#Component
public class FooBean {
#Transactional
public void foo(){}
#Transactional
public void bar(){}
}
And both methods are called from method baz of bean BazBean:
#Component
public class BazBean {
public void baz(){
foo();
bar();
}
}
If method baz already executed in transaction, i.e. it marked as transactional:
#Transactional
public void baz(){
Or BazBean marked as transactional:
#Component
#Transactional
public class BazBean {
Or as transactional marked any method up on calling stack.
Than foo and bar will be executed in one transaction.
Otherwise foo and bar will be executed in different transactions.
Please note, that it all was described for #Transactional without parameters. See paramteter propagation for #Transactional: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html

Spring managed transactions #Transactional annotation

Propagation setting is REQUIRED.
#Transactional(propagation = Propagation.REQUIRED)
Transaction is read/write.
In which scenario those are used? Please give me explain with example
Spring transaction default is
#Transactional(propagation = Propagation.REQUIRED)
So you do not need to specify the propagation property.
So, What does it mean by #Transactional annotation for a spring component ?
Spring framework will start a new transaction and executes all the method and finally commit the transaction.
But If no transaction is exists in the application context then spring container will start a new transaction.
If more than one method configured as Propagation.REQUIRED then transactional behavior assigned in a nested way to each method in logically but they are all under the same physical transaction.
So, What is the result ?
The result is if any nested transaction fail, then the whole transaction will fail and rolled back (do not insert any value in db) instead of commit.
Example:
#Service
public class ServiceA{
#Transactional(propagation = Propagation.REQUIRED)
public void foo(){
fooB();
}
#Transactional(propagation = Propagation.REQUIRED)
public void fooB(){
//some operation
}
}
Explanation :
In this example foo() method assigned a transactional behavior and inside foo() another method fooB() called which is also transactional.
Here the fooB() act as nested transaction in terms of foo(). If fooB() fails for any reason then foo() also failed to commit. Rather it roll back.
This annotation is just to help the Spring framework to manage your database transaction.
Lets say you have a service bean that writes to your database and you want to make sure that the writing is done within a transaction then you use
#Transactional(propagation = Propagation.REQUIRED)
Here is a small example of a Spring service bean.
#Service
class MyService {
#Transactional(propagation = Propagation.REQUIRED)
public void writeStuff() {
// write something to your database
}
}
The Transactional annotation tells Spring that:
This service method requires to be executed within a transaction.
If an exception gets thrown while executing the service method, Spring will rollback the transaction and no data is written to the database.

Spring transaction when calling private method

I have two questions.
If I have a method:
#Transactional
public method1(){
method2()
}
public method2(){
dao.save()
}
If there is an exception in method2(), will there be a rollback?
Another question:
If I have a method:
#Transactional
public method1(){
method2()
}
private void method2(){
dao.save()
}
If there is an exception in method2(), will there be a rollback?
Yes, there will be a rollback.
The private methods will run within the same transaction. You should be aware that you can't have a #Transactional private method. It will not work without raising any error. This behavior is explained in Spring Docs:
Due to the proxy-based nature of Spring’s AOP framework, calls within
the target object are by definition not intercepted. For JDK proxies,
only public interface method calls on the proxy can be intercepted.
Yes to both. Transactional method means there must be no error during the entire runtime of the method.
If there is an error on one of the methods you are calling from within, these errors will be propagated and make the transaction fail and rollback.

Spring Data JPA - How to have multiple transaction boundaries with same TransactionManager

I have a service which has to perform the following steps in sequence.
1) insert database records
2) commit
3) call external service (This service need to see the inserts in step 1)
4) more inserts
5) commit
Currently the external service is not able to see the inserted rows.
Please suggest how to make the commit happen before the external call. I am using Spring JPA/Hibernate.
Thanks
You need to ensure both operations run in their own transaction and that T1 is committed before T2 executes. You also need to be aware of this discussion:
Spring #Transaction method call by the method within the same class, does not work?
Given the above something like this should work:
#Service
public class ClientService{
#Autowired
private RecordsService recordsService;
#Autowired
private ExternalService externalService;
public void insert(){
recordsService.insertRecords();
externalService.insertRecords();
}
}
#Service
public class RecordsService{
#Transactional
public void insertRecords(){
}
}
#Service
public class ExternalService{
#Transactional
public void insertRecords(){
}
}

Resources