Hi everybody,
I have been dealing with a problem related to Transactions and Hibernate Exceptions. I got a code that was trying to retry a transaction after a deadlock exception.
After investigating a while I found the following information on Hibernate official documentation:
http://docs.jboss.org/hibernate/core/3. ... erence.pdf (page 248)
Quote:
If the Session throws an exception, including any SQLException, immediately rollback the
database transaction, call Session.close() and discard the Session instance. Certain methods
of Session will not leave the session in a consistent state. No exception thrown by Hibernate
can be treated as recoverable. Ensure that the Session will be closed by calling close() in a
finally block.
I removed the code that was trying to retry the transaction and I got the following message:
Code:
org.hibernate.exception.LockAcquisitionException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:105)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:114)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:109)
at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:244)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2382)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2335)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2635)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
at sun.reflect.GeneratedMethodAccessor63.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
.
.
.
Caused by: java.sql.BatchUpdateException: Deadlock found when trying to get lock; try restarting transaction
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1998)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1443)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 139 more
As you see the following message appears:
Quote:
Deadlock found when trying to get lock; try restarting transaction
So should I retry the transaction after a Hibernate Exception? Or shouldn't I? Which is the correct implementation?
Code:
AttitudeRepositoryImpl.class
public void save(Object obj) {
Closure op = { Session session, Transaction transaction ->
session.saveOrUpdate(obj)
transaction.commit();
return void;
}
newCallback(op).process()
}
private Session getCurrentSession(){
return hibernate.getSessionFactory().currentSession
}
private TransactionalCallback newCallback(Closure op){
return new TransactionalCallback(getCurrentSession(), op)
}
Code:
public class TransactionalCallback {
static Logger logger = Logger.getLogger(TransactionalCallback.getName())
protected Session session
protected Transaction transaction
private Closure operation
public TransactionalCallback(Session session, Closure operation) {
this.session = session
this.transaction = session.beginTransaction()
this.operation = operation
}
protected Object process() {
try {
return operation.call(session, transaction)
}
catch (HibernateException exception) {
transaction.rollback()
logger.warn("Hibernate Exception: ${exception.getMessage()}")
throw exception
}
}
}
Thanks in advance,
Hernan