Spring transaction when calling private method - spring

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.

Related

Spring Boot - A bean referencing itself to trigger AOP #Async within the same class, not working

I want to within my own Bean call a method within itself which has its own #Async and #Transactional proxies but it isnt working.
public class MyClass {
private MyClass _selfWithProxy;
#PostConstruct
public void postContruct() {
_selfWithProxy = applicationContext.getBean(MyClass.class);
}
void myMethodA() {
_selfWithProxy.myMethodB()
}
#Async
#Transactinal
void myMethodB() {
//do stuff
}
However when I call myMethodA from another Bean the call to myMethodB does not intercept with an Async interceptor. I can see _selfWithProxy is a proxy bean, and the proxy activates but there are is no Async interceptor in the chain.
When I call myMethodB from another bean the #Async works, so I know it is setup correctly
Self invocation won't work for #Async. I believe that is because the proxy (your code + AOP advice) object calls your methodA on the target object (just your code) which then calls it's own methodB which isn't advised by AOP. In general I would not advise having spring bean methods call other methods of the same bean.
"#Async has two limitations:
It must be applied to public methods only.
Self-invocation — calling the async method from within the same class — won't work.
The reasons are simple: The method needs to be public so that it can be proxied. And self-invocation doesn't work because it bypasses the proxy and calls the underlying method directly."
https://www.baeldung.com/spring-async

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().

#Transactional in a service class with no call to database

When a service class has no implementation of Jpa repository ,My understanding is that it is wrong to annotate it with Transactional, for example this service class with should not have #Transactional
#Service
public class BillingAddressServiceImpl implements BillingAddressService {
public BillingAddress setByUserBilling(UserBilling userBilling, BillingAddress billingAddress) throws DataAccessException
{
billingAddress.setBillingAddressName(userBilling.getUserBillingName());
billingAddress.setBillingAddressStreet1(userBilling.getUserBillingStreet1());
billingAddress.setBillingAddressStreet2(userBilling.getUserBillingStreet2());
billingAddress.setBillingAddressCity(userBilling.getUserBillingCity());
billingAddress.setBillingAddressState(userBilling.getUserBillingState());
billingAddress.setBillingAddressCountry(userBilling.getUserBillingCountry());
billingAddress.setBillingAddressZipCode(userBilling.getUserBillingZipCode());
return billingAddress;
}
}
The Transactional annotation stands for declaring the database transaction handling of Spring bean methods.
Since your service method is not working with the database it makes no sense to declare a transaction handling.
Transactional annotations are only used with method or classes that makes calls to database,one of the uses of transactional annotation is rollback - which means when we make call to a database there would be a recording of the intermidiate state between the successful call and its original state, this is so that in the case of a failed call the system does not crash but is able to return to its original state

Using the default PROPAGATION_REQUIRED with #Transactional behaviour

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?

Spring transaction: requires_new beharivour

May be I am misunderstand Spring Requires_new behavior. Here is my code:
#Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRED)
public void outterMethod() throws Exception{
innerMethod1();
innerMethod2();
}
#Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRES_NEW)
public void innerMethod1() throws Exception{
testService.insert(new Testbo("test-2", new Date()));
}
#Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRES_NEW)
public void innerMethod2() throws Exception{
testService.insert(new Testbo("test-2", new Date()));
throw new Exception();
}
When the innnerMethod2 throws Exception, I thought that innerMethod1 still able to commit. But the all the outer and inner transactions rollback. What am I wrong here? How can I do to commit innerMethod1 when innerMethod2 rollback?
Although you have correctly understood the behavior of Propagation.REQUIRES_NEW, you have stumbled upon a common misconception about Spring 's Transactional behavior.
In order for the transactional semantics to be applied (that is for the annotation of the method to have any effect), the method needs to be called from outside the class. Calling a method annotated with transactional from inside the class has absolutely no effect on the transactional processing (because the Spring generated proxy class that contains the transactional code does not come into play).
In your example innerMethod2 maybe annotated with #Transactional but since it is called from outterMethod, the annotation is not being processed.
Check out this part of the Spring documentation

Resources