From 07ddedd7bf50c1015ae7fe7fd74abbf77df693e3 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 22 Dec 2011 02:51:13 +0100 Subject: [PATCH] Hibernate synchronization properly unbinds Session even in case of afterCompletion exception (SPR-8757) --- .../SpringSessionSynchronization.java | 56 +++++++++++-------- .../SpringSessionSynchronization.java | 14 +++-- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SpringSessionSynchronization.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SpringSessionSynchronization.java index aab75ceb20..240ebcbcc9 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SpringSessionSynchronization.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SpringSessionSynchronization.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -218,32 +218,40 @@ class SpringSessionSynchronization implements TransactionSynchronization, Ordere } public void afterCompletion(int status) { - if (!this.hibernateTransactionCompletion || !this.newSession) { - // No Hibernate TransactionManagerLookup: apply afterTransactionCompletion callback. - // Always perform explicit afterTransactionCompletion callback for pre-bound Session, - // even with Hibernate TransactionManagerLookup (which only applies to new Sessions). - Session session = this.sessionHolder.getSession(); - // Provide correct transaction status for releasing the Session's cache locks, - // if possible. Else, closing will release all cache locks assuming a rollback. - if (session instanceof SessionImplementor) { - ((SessionImplementor) session).afterTransactionCompletion(status == STATUS_COMMITTED, null); - } - // Close the Hibernate Session here if necessary - // (closed in beforeCompletion in case of TransactionManagerLookup). - if (this.newSession) { - SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, this.sessionFactory); + try { + if (!this.hibernateTransactionCompletion || !this.newSession) { + // No Hibernate TransactionManagerLookup: apply afterTransactionCompletion callback. + // Always perform explicit afterTransactionCompletion callback for pre-bound Session, + // even with Hibernate TransactionManagerLookup (which only applies to new Sessions). + Session session = this.sessionHolder.getSession(); + // Provide correct transaction status for releasing the Session's cache locks, + // if possible. Else, closing will release all cache locks assuming a rollback. + try { + if (session instanceof SessionImplementor) { + ((SessionImplementor) session).afterTransactionCompletion(status == STATUS_COMMITTED, null); + } + } + finally { + // Close the Hibernate Session here if necessary + // (closed in beforeCompletion in case of TransactionManagerLookup). + if (this.newSession) { + SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, this.sessionFactory); + } + else if (!this.hibernateTransactionCompletion) { + session.disconnect(); + } + } } - else if (!this.hibernateTransactionCompletion) { - session.disconnect(); + if (!this.newSession && status != STATUS_COMMITTED) { + // Clear all pending inserts/updates/deletes in the Session. + // Necessary for pre-bound Sessions, to avoid inconsistent state. + this.sessionHolder.getSession().clear(); } } - if (!this.newSession && status != STATUS_COMMITTED) { - // Clear all pending inserts/updates/deletes in the Session. - // Necessary for pre-bound Sessions, to avoid inconsistent state. - this.sessionHolder.getSession().clear(); - } - if (this.sessionHolder.doesNotHoldNonDefaultSession()) { - this.sessionHolder.setSynchronizedWithTransaction(false); + finally { + if (this.sessionHolder.doesNotHoldNonDefaultSession()) { + this.sessionHolder.setSynchronizedWithTransaction(false); + } } } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/SpringSessionSynchronization.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/SpringSessionSynchronization.java index fa49ace3f7..19f47c86fc 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/SpringSessionSynchronization.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/SpringSessionSynchronization.java @@ -111,12 +111,16 @@ class SpringSessionSynchronization implements TransactionSynchronization, Ordere } public void afterCompletion(int status) { - if (status != STATUS_COMMITTED) { - // Clear all pending inserts/updates/deletes in the Session. - // Necessary for pre-bound Sessions, to avoid inconsistent state. - this.sessionHolder.getSession().clear(); + try { + if (status != STATUS_COMMITTED) { + // Clear all pending inserts/updates/deletes in the Session. + // Necessary for pre-bound Sessions, to avoid inconsistent state. + this.sessionHolder.getSession().clear(); + } + } + finally { + this.sessionHolder.setSynchronizedWithTransaction(false); } - this.sessionHolder.setSynchronizedWithTransaction(false); } }