Spring + Hibernate how to prevent rollback - spring

I have a code block with this method:
#Transactional(noRollbackFor=Exception.class)
public synchronized Object saveData(){
//...
dao.insert(entity);
//...
}
My dao class is marked ad Transactional
#Transactional
public class Dao {
//...
public <T> void insert(T obj) throws Exception {
getSession().saveOrUpdate(obj);
}
}
I need to prevent any rollback inside this block. However I got this:
2014-02-25 20:47:44 [WARN]SqlExceptionHelper:143 SQL Error: 1205, SQLState: 41000
2014-02-25 20:47:44 [ERROR]SqlExceptionHelper:144 Lock wait timeout exceeded; try restarting transaction
2014-02-25 20:47:44 [ERROR]BigliettiService:? Transazione in errore
org.hibernate.exception.GenericJDBCException: Lock wait timeout exceeded; try restarting transaction
...
2014-02-25 20:47:44 [ERROR]JsonHandlerExceptionResolver:? Transaction rolled back because it has been marked as rollback-only
Why at the end I found a Transaction rolled back?

I had a similar issue just last week. In my case it was another #Transactional annotation from a different method that caused the transaction to be marked as rollback-only.
Did you check for that yet?
Edit: To clarify it a bit more, you didn't post your code from inside your saveData() method. What caused this error for me was calling another method with #Transactional (lacking the noRollback attribute) from inside my method, in your case saveData().

I don't think you can do that. Your transaction is being propagated by default to the inner method and if this method rollbacks your transaction, the outer method can only be notified by a UnexpectedRollbackException that the rollback already happened.. and acknowledge it.
You can change the propagation config to start a new inner transaction but this won't help as it will still be commited independently before reaching the outer transaction.
If you can't set a NoRollback attribute at DAO level, I guess the best solution would be to remove the Transactional attributes from your DAOs and have a layer of facade services calling these DAOs and defining their own rollback strategies.

Related

Spring Transactional on method with multiple db operation

I'm little confused. I though #Transactional on method means all operations or none.
Say I have this method:
#Transactional
public void fewDbOpeations(){
calculation1();
myDao.saveResult();
calculation2();
myDao.saveResult();
}
Say calculation2() throw exception or my second call to myDao.saveResult goes wrong , what I see is the even though the whole method annotated with #Transactional the saving result after calculation1() call is successful.
That is my first interaction with database saved the records I want but the second one failed but I thought because the method is #Transactinal even the first call to save to database should be rolled back.
Do I miss something?
#Transactional (rollbackFor = Exception.class)
public void fewDbOpeations(){
calculation1();
myDao.saveResult();
calculation2();
myDao.saveResult();
}
Try using this as well and throw Exceptions.
It depends on how you handle exceptions and if there are still #Transactional annotated on those internal method calls.
To have "all or nothing" behaviour in fewDbOpeations(), make sure the followings for all the internal method calls :
Do not annotated with #Transactional(propagation=REQUIRES_NEW)
Do not catch the exception inside and not throw out. Throw RuntimeException or Error but not checked Exception (Assume you are using default setting).

Multiple transaction management in Spring JPA

I am using Spring 4, JPA and Hibernate 5. I have a service as follows:
#Transactional(rollbackFor = Exception.class)
public methodA() {
// do some stuff
methodB();
}
#Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public methodB() {
try {
methodC();
} catch (Exception e) {
// only log
}
}
#Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public methodC() {
// do some stuff
}
What I want to achieve is this: when methodA is called, everything executed before calling methodB should be persisted, independently to what happens afterwards. For this reason I added methodB, the only purpose of which is to create a new transaction, so if the transaction of methodC rollbacks, the original transaction of methodA does not rollback as well. So to sum this up, I want the first transaction to commit and the second to rollback in case of failure. Note that methodC cannot be changed in any way.
This code however does not work and I still get the exception: "TransactionException: Transaction was marked for rollback only; cannot commit"
Any ideas on what I'm doing wrong?
I am using Spring 4, JPA and Hibernate 5. I have a service as follows:
So you're using three methods inside same service
This highlight is important because of how spring AOP works.
If you call method within the same class, then the other methods do not get proxied by #Transaction so they're still using the same transaction of methodA.
Therefore you will see exception when the transaction is marked as rollbackOnly by methodB
So to solve this: You have to move the method methodB to another service so it will proxy-able by Spring.

Grails/Spring REQUIRES_NEW rolling back outer transaction

REQUIRES_NEW is rolling back all transactions:
I have a method marked #Transactional(propagation = REQUIRES_NEW)
within a bean that also has methods marked #Transactional(propagation = REQUIRED). These methods never call each other. They are called from another bean individually. However when my method that has been marked with REQUIRES_NEW fails, it rolls back the whole transaction, including the methods that are marked REQUIRED (which is problematic).
My understanding is that if factored this way Spring AOP will have a chance to intercept the REQUIRES_NEW method and start a new logical transaction.
The general idea looks like this:
#Transactional
class TransactionalBean{
#Transactional(propagation = REQUIRED)
public void methodA(){ //do transactional work }
#Transactional(propagation = REQUIRES_NEW)
public void methodB(){ //do transactional work }
}
And then the calling bean looks like so:
#Transactional
class CallingBean{
#Autowired
TransactionalBean
public void doWork(){
TransactionalBean.methodA();
TransactionalBean.methodB();
}
}
So if method A and B succeed, everything is fine. However when method B fails work done in method A gets rolled back. My understanding is that when methodB() is invoked that it 'should' get intercepted by AOP and start a new transaction and suspend the other transaction, but it's not working. How do I fix this? I'm using Grails 2.5, Hibernate, JPA
The problem is with the way the CallingBean was marked as #Transactional. What is happening is that the CallingBean is creating a transaction, let's say t1. The CallingBean is invoking the two transactional methods methodA and methodB. Since methodA requires a transaction, it will make use of the existing transaction t1. However, methodB will create a new transaction as the annotation requires a new one, let's say t2. The transactional boundary of methodA does not end when the control exits methodA, but is kept alive until methodB is completed since the transaction started at the calling bean. Now that the transaction t2 is failing in methodB, the exception would bubble up to the calling bean and the transaction t1 would fail.
In order to resolve this, you can do one of the following based on your needs.
Turn off the #Transactional annotation in the CallingBean class.
//#Transactional
class CallingBean{
...
}
Update the annotation to use noRollbackFor option
#Transactional(noRollbackFor={WhateverException.class})
class CallingBean{
...
}

Spring Annotation: #Transactional

i want to make somethings clear about #Transactional spring annotation.
Suppose i have written my code something as under,
case-1
#Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor=Throwable.class)
public void method1(){
.....method body....
}
#Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor=Throwable.class)
public String method2(){
try{
method1()
}
catch(Exce...){
}
}
case 2:
#Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor=Throwable.class)
public void method1(){
try{
}
catch(Excep..){
}
}
#Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor=Throwable.class)
public String method2(){
method1()
}
What would happen in case-1 if some exception occurs in excecution of method1, does it rollback transaction?
and what would happen for the same in case-2.
Thanx in advance
There will be no rollback in any of your use cases regardless of the exception type or propagation as long as you catch the exception in method2.
Why?
Spring creates a proxy class for the Transactional class or members, this is not visible for you. This proxy makes it possible to Spring to execute code before and after your function, basically open transaction, commit or rollback. This proxy is injected into your classes when you autowire them.
Of course the Transactional annotations only work when you're calling them through the proxy!
Your method1 call is always a local function call, so as long as you catch the exception in method2 it won't cause any rollback.
But please read the documentation.
You are free to specify. Using annotations for instance you can write like this:
#Transactional(rollbackFor=Exception.class, timeout=10)
Default behavior is not to rollback when an exception is thrown across the transaction demarcation line.
The Spring #Transactional default configuration (as you used it here) is rolling back only for java.lang.RuntimeException s and the propagation is REQUIRED.
So in case you are calling method2():
CASE 1: no rollback as you are catching in method2() java.lang.Exception (which is the parent of java.lang.RuntimeException)
CASE 2: same - as you are catching in method1() java.lang.Exception
The meaning of the propagation here is that when you've started a transaction if you encounter another annotation of #Transaction another transaction is not started and the application uses the "outer" transaction. So do not expect that the rollback logic will get executed before the method2() finishes. Anyway, one may assume from your snippet that the methods are in the same Spring Bean so calling a method internally in a bean (method2() calls method1() here) the AOP annotation are not "active" meaning that the f/w will not even "see" the #Transactionl on method1().
EDIT
Question changed so that the rollback is for all java.lang.Throwable s. So the answer is the same except for the fact that if an java.lang.Error is thrown then there is a rollback in both cases after the method2() is finished.

Propagation required clariification spring

wanted to clarify the Propagation required fundamental with below scenarios. . Please let me know if below understanding is correct.
Class MyClass1{
//Propagation is Propagation required
public void method1();
{
method1A();
method1B();
MyClass2 myClass2= new MyClass2();
myClass2.method2A();
myClass2.method2B();
}
// No porapgation is defined here so default will be reuired
public method1A()
{
//Some Transaction
}
// No porapgation is defined here so default will be reuired
private method1B()
{
//Some Transaction
}
}
Class MyClass2{
//Propagation is Propagation required
public void method2()
{
method2A();
method2B();
}
// No porapgation is defined here so default will be required
public method2A()
{
//Some Transaction
}
// No porapgation is defined here so default will be required
public method2B()
{
//Some Transaction
}
}
Now here are the scenarios
we call the method1() of MyClass1 inside main method
Scenarion1:-
No exception occurs. transaction will be created before method1A() and will be commited after myClass2.method2B();
Scenarion2:-
Runtime exception occurs during method1B. Complete transaction will be rolled back
Scenarion3:-
Runtime exception occurs during method2A(Transaction under method2A will be treated as part of transaction created
under method1 in class1) .Complete transaction will be rolled back
Scenarion4:-
Runtime exception occurs during method2B(Transaction under method2A will be treated as part of transaction created
under method1 in class1) .Complete transaction will be rolled back
Edit:-
Now if we consider the same scenarios with propagation as Nested for methods method2A and method2B.
Scenarion1:-
No exception occurs. transaction will be created on entering method1A() and will be commited on exit of method1A()
Scenarion2:-
Runtime exception occurs during method1B. Complete transaction will be rolled back
Scenarion3:-
Runtime exception occurs during method2A .Only transaction under method2A will be rolled back and rest of the transaction will be commited
on exit of method1
Scenarion4:-
Runtime exception occurs during method2B. Only transaction under method2B will be rolled back and rest of the transaction will be commited
on exit of method1
Your understanding is (generally) correct, but your example is flawed. By calling:
MyClass2 myClass2= new MyClass2();
You've ensured that method calls on myClass2 will not be intercepted by the transactional proxy, and therefore any propagation required semantics implied here don't really matter since they won't be applied. In this case, however, you will fall within the transactional boundaries of method1 and since you've marked it as propagation required, your code will execute as you've described. You would do well to come up with a SSCCE if you require further clarification.
Also, the Spring documentation on Transaction Management is some of the best you'll find, I highly recommend you take a look at it.

Resources