All I know about this exception is from Spring's documentation and some forum posts with frostrated developers pasting huge stack traces, and no replies.
From Spring's documentation:
Thrown when an attempt to commit a transaction resulted in an unexpected rollback
I want to understand once and for all
Exactly what causes it?
Where did the rollback occur? in the App Server code or in the Database?
Was it caused due to a specific underlying exception (e.g. something from java.sql.*)?
Is it related to Hibernate? Is it related to Spring Transaction Manager (non JTA in my case)?
How to avoid it? is there any best practice to avoid it?
How to debug it? it seems to be hard to reproduce, any proven ways to troubleshoot it?
I found this to be answering the rest of question: https://jira.springsource.org/browse/SPR-3452
I guess we need to differentiate
between 'logical' transaction scopes
and 'physical' transactions here...
What PROPAGATION_REQUIRED creates is a
logical transaction scope for each
method that it gets applied to. Each
such logical transaction scope can
individually decide on rollback-only
status, with an outer transaction
scope being logically independent from
the inner transaction scope. Of
course, in case of standard
PROPAGATION_REQUIRED behavior, they
will be mapped to the same physical
transaction. So a rollback-only marker
set in the inner transaction scope
does affect the outer transaction's
chance to actually commit. However,
since the outer transaction scope did
not decide on a rollback itself, the
rollback (silently triggered by the
inner transaction scope) comes
unexpected at that level - which is
why an UnexpectedRollbackException
gets thrown.
PROPAGATION_REQUIRES_NEW, in contrast,
uses a completely independent
transaction for each affected
transaction scope. In that case, the
underlying physical transactions will
be different and hence can commit or
rollback independently, with an outer
transaction not affected by an inner
transaction's rollback status.
PROPAGATION_NESTED is different again
in that it uses a single physical
transaction with multiple savepoints
that it can roll back to. Such partial
rollbacks allow an inner transaction
scope to trigger a rollback for its
scope, with the outer transaction
being able to continue the physical
transaction despite some operations
having been rolled back. This is
typically mapped onto JDBC savepoints,
so will only work with JDBC resource
transactions (Spring's
DataSourceTransactionManager).
To complete the discussion:
UnexpectedRollbackException may also
be thrown without the application ever
having set a rollback-only marker
itself. Instead, the transaction
infrastructure may have decided that
the only possible outcome is a
rollback, due to constraints in the
current transaction state. This is
particularly relevant with XA
transactions.
As I suggested above, throwing an
exception at the inner transaction
scope, then catching that exception at
the outer scope and translating it
into a silent setRollbackOnly call
there should work for your scenario. A
caller of the outer transaction will
never see an exception then. Since you
only worry about such silent rollbacks
because of special requirements
imposed by a caller, I would even
argue that the correct architectural
solution is to use exceptions within
the service layer, and to translate
those exceptions into silent rollbacks
at the service facade level (right
before returning to that special
caller).
Since your problem is possibly not
only about rollback exceptions, but
rather about any exceptions thrown
from your service layer, you could
even use standard exception-driven
rollbacks all the way throughout you
service layer, and then catch and log
such exceptions once the transaction
has already completed, in some
adapting service facade that
translates your service layer's
exceptions into UI-specific error
states.
Juergen
Scroll a little more back in the log (or increase it's buffer-size) and you will see what exactly caused the exception.
If it happens not to be there, check the getMostSpecificCause() and getRootCause() methods of UnexpectedRollbackException- they might be useful.
Well I can tell you how to reproduce the UnexpectedRollbackException. I was working on my project, and I got this UnexpectedRollbackException in following situation. I am having controller, service and dao layers in my project.
What I did is in my service layer class,
class SomeServiceClass {
void outerTransaction() {
// some lines of code
innerTransaction();
//AbstractPlatformTransactionManager tries to commit but UnexpectedRollbackException is thrown, not here but in controller layer class that uses SomeServiceClass.
}
void innerTransaction() {
try {
// someDaoMethod or someDaoOperation that throws exception
} catch(Exception e) {
// when exception is caught, transaction is rolled back, outer transaction does not know about it.
// I got this point where inner transaction gets rolled back when I set HibernateTransactionManager.setFailEarlyOnGlobalRollbackOnly(true)
// FYI : use of following second dao access is wrong,
try {
// again some dao operation
} catch(Exception e1) {
throw e2;
}
}
}
}
I had this problem with Spring Framework 4 + Java 1.8 for this exception.
I solved it.
😊
I know that runtime exceptions rollbacks.
But in my case, project do not use runtime exceptions.
For example, we have code.
#Transactional
#Service
UserFacadeIml implements UserFacade
{
#Autowired
private UserService userService;
//throws UnexpectedRollbackException
//instead NotRuntimeEx
#Override
public void saveUser(User user)
throws NotRuntimeEx
{
return userService.saveUser(user);
}
}
I solved it, when add "Transactional(rollBackFor=NotRuntimeEx.class)" for facade.
It works, because Spring use proxy for facade and proxy for service.
When transactional rollback, proxy of service send context to facade.
But facade proxy does not understand, why transaction rollback.
#Transactional(rollBackFor=NotRuntimeEx.class)
#Service
UserServiceIml implements UserService
{
#Override
public void saveUser(User user)
throws NotRuntimeEx
{
throw new NotRuntimeEx(user);
}
}
Related
It's not exactly as the title says, but close to. Consider these Spring beans:
#Bean
class BeanA {
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = EvilException.class)
public void methodA() {
/* ... some actions */
if (condition) {
throw new EvilException();
}
}
}
#Bean
class BeanB {
#Autowired private BeanA beanA;
final int MAX_TRIES = 3;
#Transactional(propagation = Propagation.NESTED)
public void methodB() {
// prepare to call Bean A
try {
beanA.methodA();
/* maybe do some more things */
}
catch (EvilException e) {
/* recover from evil */
}
}
}
#Bean
class MainWorkerBean {
#Autowired private BeanB beanB;
#Autowired private OtherBean otherBean;
#Transactional(propagation = Propagation.REQUIRED)
public void doSomeWork() {
beanB.methodB();
otherBean.doSomeWork();
}
}
Important note: I'm using JDBC transaction manager that supports savepoints.
What I'm expecting this to do is, when EvilException is thrown, the transaction of the BeanA is rolled back, which with this setup happens to be the savepoint created by starting methodB. However, this appears to not be the case.
When going over with debugging tools, what I'm seeing is this:
When doSomeWork of MainWorkerBean starts, new transaction is created
When methodB starts, transaction manager properly initializes a savepoint and hands it to TransactionInterceptor
When methodA starts, transaction manager sees Propagation.REQUIRED again, and hands out a clean reference to the actual JDBC transaction again, that has no knowledge of the savepoint
This means that when exception is thrown, TransactionStatus::hasSavepoint return false, which leads to roll back of the whole global transaction, so recovery and further steps are as good as lost, but my actual code has no knowledge of the rollback (since I've written recovery for it).
For now, I can't consider changing BeanA's transaction to Propagation.NESTED. Admittedly, looks like it's going to allow me to have the more local rollback, but it's going to be too local, because as I understand it, Spring then will have two savepoints, and only roll back the BeanA savepoint, not BeanB one, as I'd like.
Is there anything else I'm missing, such as a configuration option, that would make internal transaction with Propagation.REQUIRED consider that it is running inside a savepoint, and roll back to savepoint, not the whole thing?
Right now we're using Spring 4.3.24, but I already crawled through their code and can't spot any relevant changes, so I don't think upgrading will help me.
As described in this bug ticket: https://github.com/spring-projects/spring-framework/issues/11234
For spring versions < 5.0, in the situation described, the global transaction is set to 'rollback-only'.
In this transaction I am processing several tasks. If an error should occur during a single task, I do not want the whole transaction to be rolled back, therefore I wrap the task processing in another transaction boundary with a propagation of PROPAGATION_NESTED.
The problem comes when, during task processing, calls are made to existing service methods defined with a transaction boundary of PROPAGATION_REQUIRED. Any runtime exceptions thrown from these methods cause the underlying connection to be marked as rollback-only, rather than respecting the current parent transaction nested propagation.
[...]
As of Spring Framework 5.0, nested transactions resolve their rollback-only status on a rollback to a savepoint, not applying it to the global transaction anymore.
On older versions, the recommended workaround is to switch globalRollbackOnParticipationFailure to false in such scenarios.
However, even for Spring5, I noticed when reproducing the problem, that the nested transaction may be rolled back, including all things done in the catch block of methodB(). So your recover code might not work inside methodB(), depending on what your recovery looks like. If methodA() was not transactional, that would not happen. Just something to watch out for.
Some more details to be found here: https://github.com/spring-projects/spring-framework/issues/8135
I have a question regarding #Transactional annotation.
Nothing special defined, so as I understand is PROPAGATION_REQUIRED
Let’s say I have a transactional annotation which on both service and dao layer.
Service
#Transactional
public long createStudentInDB(Student student) {
final long id = addStudentToDB (student);
addStudentToCourses (id, student.getCourseIds());
return id;
}
private long addStudentToDB (Student student) {
StudentEntity entity = new StudentEntity ();
convertToEntity(student, entity);
try {
final id = dao.create(entity);
} catch (Exception e){
//
}
return id;
}
private void addStudentToCourses (long studentId, List<String> coursesIds){
//add user to group
if(coursesIds!= null){
List<StudentCourseEntity> studentCourses = new ArrayList<>();
for(String coursesId: coursesIds){
StudentCourseEntity entity = new StudentCourseEntity ();
entity.setCourseId(coursesId);
entity.setStudentId(userId);
studentCourses.add(studentId);
}
anotherDao.saveAll(studentCourses);
}
}
DAO
#Transactional
public UUID create(StudentEntity entity) {
if ( entity == null ) { throw new Exception(//…); }
getCurrentSession().save(entity);
return entity.getId();
}
ANOTHER DAO:
#Transactional
public void saveAll(Collection< StudentCourseEntity > studentCourses) {
List< StudentCourseEntity > result = new ArrayList<>();
if(studentCourses!= null) {
for (StudentCourseEntity studentCourse : studentCourses) {
if (studentCourse!= null) {
save(studentCourse);
}
}
}
}
Despite the fact that’s not optimal, it seems it causing deadlocks.
Let’s say I have max 2 connections to the database.
And I am using 3 different threads to run the same code.
Thread-1 and thread-2 receive a connection, thread-3 is not getting any connection.
More than that, it seems that thread-1 become stuck when trying to get a connection in dao level, same for thread-2. Causing a deadlock.
I was sure that by using propagation_required this would not happen.
Am I missing something?
What’s the recommendation for something like that? Is there a way I can have #transactional on both layers? If not which is preferred?
Thanks
Fabrizio
As the dao.doSomeStuff is expected to be invoked from within other transactions I would suggest you to configure this method as:
#Transaction(propagation=REQUIRES_NEW)
Thanks to that the transaction which is invoking this method will halted until the one with REQUIRES_NEW will be finished.
Not sure if this is the fix for your particular deadlock case but your example fits this particular set-up.
You are right, Propagation.REQUIRED is the default. But that also means that the second (nested) invocation on dao joins / reuses the transaction created on service level. So there is no need to create another transaction for the nested call.
In general Spring (on high level usage) should manage resource handling by forwarding it to the underlying ORM layer:
The preferred approach is to use Spring's highest level template based
persistence integration APIs or to use native ORM APIs with
transaction- aware factory beans or proxies for managing the native
resource factories. These transaction-aware solutions internally
handle resource creation and reuse, cleanup, optional transaction
synchronization of the resources, and exception mapping. Thus user
data access code does not have to address these tasks, but can be
focused purely on non-boilerplate persistence logic.
Even if you handle it on your own (on low level API usage) the connections should be reused:
When you want the application code to deal directly with the resource
types of the native persistence APIs, you use these classes to ensure
that proper Spring Framework-managed instances are obtained,
transactions are (optionally) synchronized, and exceptions that occur
in the process are properly mapped to a consistent API.
...
If an existing transaction already has a connection synchronized
(linked) to it, that instance is returned. Otherwise, the method call
triggers the creation of a new connection, which is (optionally)
synchronized to any existing transaction, and made available for
subsequent reuse in that same transaction.
Source
Maybe you have to find out what is happening down there.
Each Session / Unit of Work will be bound to a thread and released (together with the assigned connection) after the transaction has ended. Of course when your thread gets stuck it won't release the connection.
Are you sure that this 'deadlock' is caused by this nesting? Maybe that has another reason. Do you have some test code for this example? Or a thread dump or something?
#Transactional works by keeping ThreadLocal state, which can be accessed by the (Spring managed) Proxy EntityManager. If you are using Propagation.REQUIRED (the default), and you have a non-transactional method which calls two different DAOs (or two Transactional methods on the same DAO), you will get two transactions, and two calls to acquire a pooled connection. You may get the same connection twice or two different connections, but you should only use one connection at the time.
If you call two DAOs from a #Transactional method, there will only be one transaction, as the DAO will find and join the existing transaction found in the ThreadLocal state, again you only need one connection from the pool.
If you get a deadlock then something is very wrong, and you may want to debug when your connections and transaction are created. A transaction is started by calling Connection.setAutoCommit(false), in Hibernate this happens in org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor#begin(). Connections are managed by a class extending org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor so these are some good places to put a break point, and trace the call-stack back to your code to see which lines created connections.
I have two methods annotated with transactional (they are on the same level - have the same parent transaction, as sketched below):
#javax.transaction.Transactional
persist() {
persistEntities1()
persistEntities2()
}
#javax.transaction.Transactional(value = Transactional.TxType.REQUIRES_NEW)
persistEntities1() {}
#javax.transaction.Transactional(value = Transactional.TxType.REQUIRES_NEW)
persistEntities2() {}
In persistEntities1 everything is OK, there is a merge call on EntityManager instance.
In persistEntities2 there is an uncaught exception.
Problem: entities that should get persisted in persistEntities1 do not get persisted.
Why is this happening? I thought that REQUIRES_NEW ensures that transaction gets committed at the end of method.
I am using Wildfly 8.2.
The solution was to move both methods persistEntities1 and persistEntities2to separate bean. Now the behavior is as expected.
It seems that this specific jpa implementation ignores child transaction annotations if child methods live in same bean as parent method.
The reason that would happen is because a RuntimeException was thrown within the execution of persistEntities1().
See why does transaction roll back on RuntimeException but not SQLException.
It doesn't seem to matter whether the exception has been caught and handled or not, the transaction context still gets set to "rollback only".
In Spring how can we make sure that certain operations are always executed together. If any one of them fails, the entire transaction needs to be rolled back. I searched this a lot and found #Transactional(propagation = Propagation.REQUIRED) annotations and TransactionTemplate.execute() methods close to my problem. Kindly clarify and help.
Both #Transactional and TransactionTemplate ensure atomicity. #Transactional is for declarative transaction management, TransactionTemplate is for programmatic transaction management. You should choose one.
The idea of transaction propagation applies only to declarative transaction management and defines a transaction behaviour when it is executed in more than one method. Note that Propagation.REQUIRED is default for Transactional.propagation. It means Support a current transaction (that is if a transaction was already started in the calling method) or create a new one if none exists.
#Transactional(propagation = Propagation.REQUIRED
May solve your problem.
Suppose in your Impl there is a method Excecute.Inside Excecute method there are other M1(),M2(),M3(),M4(),M5() methods.
May be you trying to say if for M1(),M2().M3().M4() methods Db operation succedded and at last for M5() it throws some exception then M1() to M5() all db operation should be rollback
Execute(){
M1();
M2();
M3();
M4();
M5();
if(Any error in any methods transaction will be roll back).As single trasaction object is used for all methods i.e(M1 to M5) when #Transactional(propagation = Propagation.REQUIRED is used.
}
You can create a single method that delegates to the two database calls and annotate that with #Transactional, e.g.
#Transactional
public void atomicOperation(...) {
dbCall();
logicOperation();
}
If either one fails, e.g. an exception is thrown, the entire operation will rollback. The Spring Reference Documentation has dedicated a chapter for transactions, for example there is information about #Transactional settings and Transaction propagation.
The situation is as follows:
Method1 has four database update methods in it. The Method1 is annotated using the Spring transaction management semantics.
Method2 has a database read method in it and it is invoked after Method1 has finished executing all its database updates. Method2 is also annotated using the Spring transaction semantics.
There's a web request that comes in, the controller intercepts the request and invokes method1 and then method2.
A transaction is wrapped around the web-request as well.
What I am interested in knowing is:
1.How does Spring know to commit the database updates upon a successful transaction? Is there some reference to the Spring implementation that does the transaction management?
2.Since we have a hierarchy of transactions:
Transaction around the web-request->Transaction with Propagation=RequestNew for Method1->Transaction with Propagation=Required for Method2, how does Spring do the transaction management to ensure the transactions are executed within the proper context with the right order?
In short, it will be great to get a play by play account of how Spring performs the transaction management in all its grittiest details or a reference to documentation that doesn't simply hand-wave an explanation centered around JTA or some other acronym.
Thanks
Lets make some basic statements.
A transactional context is an environment where some special properties (database session) are made available to the application runtime which are otherwise not available. A Transaction Context is generally used to scope a transaction.
Spring uses, AOP Proxies and XML metadata to achieve a Declarative transaction management.
Annotations are used to mark the Transaction Propagation behavior of a particular method.
Spring uses Interceptor Mechanism to apply the transaction over the methods.
Here I am reusing the example give by #stacker above
MyClass{
#Transactional
public void sequence() {
method1();
method2();
}
#Transactional
void method1() {
}
#Transactional(propagation=Propagation.REQUIRES_NEW)
void method2() {
}
}
You can also achieve the same functionality using xml configuration as well. Lets take this as its popular and widely used.
At the time of deployment
Spring framework checks the xml configuration files (famed applicationContext.xml) and depending on the configuration, scans the code for #Transactional annotation (assuming that the configuration is mentioned as annotation based).
After this, it generates AOP proxies for methods marked for transaction. In simple terms, these proxies are nothing but wrapper around the concerned methods.
Within these wrapper methods, before and after a Transaction Advisor code is also generated depending on the configuration (namely the transaction propagation).
Now when these wrapper methods are invoked Transaction Advisor comes into picture before and after the actual method call. .
Representing the same in pseudo code for the example above
ProxyMyClass{
MyClass myclass;
.
.
.
sequence(){
//Transaction Advisor code (Typically begin/check for transaction)
myclass.sequence();
//Transaction Advisor code(Typically rollback/commit)
}
.
.
.
}
This is how spring managers the transaction. A slight oversimplification though.
Now to answer your questions,
.How does Spring know to commit the database updates upon a successful transaction? Is there some reference to the Spring implementation that does the transaction management?
Whenever you call a method under transaction, you actually call a proxy which first executes the transaction advisor (which will begin the transaction), then you call the actual business method, once that completes, another transaction advisor executes (which depending on way method returned, will commit or rollback transaction).
Since we have a hierarchy of transactions: Transaction around the web-request->Transaction with Propagation=RequestNew for Method1->Transaction with Propagation=Required for Method2, how does Spring do the transaction management to ensure the transactions are executed within the proper context with the right order?
In case of transaction hierarchy, the spring framework generates the Transaction Advisor checks accordingly. For the example you mentioned,
for method1 (RequestNew ) Transaction Advsor code (or transaction Advice) would be to create a new transaction always.
for method2 (Required ) Transaction Advisor code (or transaction Advice) would be check for existing transaction and use the same if it exists or else create a new transaction.
There is an image on the spring documentation page which very nicely summarizes these aspects.
Hope this helps.
Controller
#Transactional
public void sequence() {
method1();
method2();
}
#Transactional
void method1() {
}
#Transactional(propagation=Propagation.REQUIRES_NEW)
void method2() {
}
The default propagation is REQUIRED (Support a current transaction, create a new one if none exists.) Therefore m1 will use the Transaction started in the Controller. m2 is annotated as REQUIRES_NEW ( Create a new transaction, suspend the current transaction if one exists.) The order of the transaction is the order you call the transactional methods.
Controller
begin tx1
|--------------------> m1 (uses tx1)
|
| begin tx2
|--------------------> m2 (uses tx2)
| commit tx2
commit tx1
Have you read the Spring documentation? Basically AOP is used to manage the transaction. You should also read the AOP documentation. If the AOP documentation is not enough I suggest you go through the code. Stepping through the code in debug mode with break-point would be good.