Currently we are facing a spring transaction related issue in our application.
As you can see that in deleteRecord()
we are doing a DB operation. But in the next line
a business exception is thrown.
Expected Behavior(As per my knowledge) : The DB operation should be rolled back as exception is thrown from the next line
Actual Behavior : Its not getting rolled back. Data is getting inserted to the table
Question :
Why transaction is not getting rolled back ? I dont think its because of the catch block
because deleteRecord()
will be executed in new transaction. Please correct me if I am wrong
Code:
class A {
void myMethod() {
for(int i=0 ; i<count ; i++) {
try {
deleteRecord();
} catch(Exception e) {
log.error("Exception caught");
}
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
deleteRecord() throws Exception{
line 1 : deleting record
line 2 : Throwing business exception
}
}
The Spring documentation says the following:
While the EJB default behavior is for the EJB container to automatically roll back the transaction on a system exception (usually a runtime exception), EJB CMT does not roll back the transaction automatically on an application exception (that is, a checked exception other than java.rmi.RemoteException). While the Spring default behavior for declarative transaction management follows EJB convention (roll back is automatic only on unchecked exceptions), it is often useful to customize this.
And
In its default configuration, the Spring Framework’s transaction infrastructure code only marks a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception is an instance or subclass of RuntimeException. ( Errors will also - by default - result in a rollback). Checked exceptions that are thrown from a transactional method do not result in rollback in the default configuration
see in 16.5.3: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html
This says that the default behavior of the transaction will only rollback for RuntimeException
s. If you have a own business exception (could be a checked excpetion), you have to explicitly name the exception class the transaction should rollback for:
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = YOUREXCEPTION.class)