To rollback when have error, I use javax.ejb.SessionContext to do that,
first I mark a point to rollback by sessionContext.getUserTransaction().begin()
Then I use sessionContext.getUserTransaction().rollback() to rollback and use sessionContext.getUserTransaction().commit(); to should complete transaction before returning.
but the problem is if there is nothing changed, this will throws org.hibernate.exception.GenericJDBCException: could not prepare statement.
Conclusion: There is anyway to stop SessionContext ?
Related
My Spring/Java web application has #Transactional services that can touch the database:
#Transactional
public class AbstractDBService { ... }
Desired functionality is for any uncaught throwable that propagates up beyond the service layer to cause a rollback. Was a bit surprised this isn't the default behaviour but after a bit of googling tried:
#Transactional(rollbackFor = Exception.class)
This seems to work except when an exception is deliberately swallowed and not rethrown. (The particular case is when an entity is not found. Guess this could be redesigned to not throw an Exception but expect there will inevitably be others - e.g. one that springs to mind is an InterruptedException when using Thread.sleep()). Then Spring complains:
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is
javax.persistence.RollbackException: Transaction marked as
rollbackOnly
...truncated..
Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:58)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)
Am I missing something here?... Is there a way to tell Spring to rollback on all uncaught throwables?
If you want to rollback on all uncaught Throwables, you can specify that in the annotation:
#Transactional(rollbackFor = Throwable.class)
By default Spring doesn't rollback for Error subclasses, probably because it seems doubtful once an Error is thrown that the JVM will be in a good enough state to do anything about it anyway, at that point the transaction can just time out. (If you try to rollback when an OutOfMemoryError is raised, the most likely outcome is another OutOfMemoryError.) So you may not gain much with this.
When you mention the case of swallowing an exception, there's no way Spring can be expected to know about it because the exception is not finding its way to Spring's proxy (which is implementing the transactional functionality). This is what happens in your RollbackException example, Hibernate has figured out the transaction needs to rollback but Spring didn't get the memo because somebody ate the exception. So Spring isn't rolling the transaction back, it thinks everything is ok and tries to commit, but the commit fails due to Hibernate having marked the transaction rollback-only.
The answer is to not swallow those exceptions but let them be thrown; making them unchecked is supposed to make it easier for you to do the right thing. There should be an exception handler set up to receive exceptions thrown from the controllers, most exceptions thrown at any level of the application can be caught there and logged.
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".
I suppose the following stacktrace as java invocation:
B.method2 (annotated with a plain #Transactional)
A.method1 (annotated with a plain #Transactional)
Main.main (starting point of the call, with no current transaction)
I expect that a transaction is started when A.method1 is entered - and the transaction will be commited (or rolled back) when A.method1 is left. I also expect that the same transaction will be used within B.method2.
A RuntimeException is thrown from within B.method2. This is a Exception that is 'listed' for rollbackFor by default. The Exception is catched within A.method1, but it will pass the boundary of #Transactional when leaving B.method2.
This is my question: Will the (current) transaction be marked for rollback or not?
The default propagation mode is REQUIRED and method2 will use transaction started for method1. On exception this transaction will be marked for rollback, so nothing will be committed to the database. You may get UnexpectedRollbackException after method1.
This is not a desired behavior since code which started the transaction (owns it) should be in control of rollback/commit. I would reorganize your code to avoid such possibility.
I am new to Spring and hibernate please help,
I am using (Jboss 6.0 Final as Server)
org.springframework.transaction.jta.JtaTransactionManager
as bean with properties set
transactionManagerName as java:/TransactionManager and
userTransactionName as java:comp/UserTransaction.
In code I have set jtaTxManager property thr setters.
Then
javax.transaction.TransactionManager tx = jtaTxManager.getTransactionManager();
and then transaction is started using tx.begin() statement.
I have used sessionFactory.getCurrentSession() to get session of hibernate
at last I have used
tx.commit()
I am using hibernate to save multiple records within jta transaction
but If in between any database error occurs between some record like constraint violation exception getting thrown on tx.commit() which is javax.transaction.RollbackException which when catch I used to call tx.rollback() but my transaction is not getting rollback and getting following exception on tx.rollback().I have not set any type auto commit property in hibernate properties.
But my first of records in gets saved in database ideally they should not saved but while rollback this exception occurs so i think that's why they are getting saved.
java.lang.IllegalStateException: BaseTransaction.rollback - [com.arjuna.ats.internal.jta.transaction.arjunacore.notx] [com.arjuna.ats.internal.jta.transaction.arjunacore.notx] no transaction!
at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.rollback(BaseTransaction.java:158)
at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.rollback(BaseTransactionManagerDelegate.java:114)
This issue was due to datasource configuration, forgot to mentioned earlier,
Removed from application-context.xml
org.springframework.jdbc.datasource.DriverManagerDataSource
and rather than this, used jndi datasorce of jboss configured in oracle-xa-ds.xml
The Javadoc states that the RollbackException gets thrown when the transaction has been rolledback instead of commited - you don't have to rollback it manually in such a case, I think.
http://download.oracle.com/javaee/6/api/javax/transaction/Transaction.html#commit%28%29
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);
}
}