Updated to work correctly with the Spring HibernateTransactionManager. Did not bind transaction as well as session causing the HTM to try and manage transactions itself.

This commit is contained in:
Ben Hale
2007-06-07 14:34:30 +00:00
parent 840239966c
commit 0a657696ce

View File

@@ -18,10 +18,13 @@ package org.springframework.webflow.support.persistence;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.execution.FlowExecution;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.FlowExecutionListener;
import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
import org.springframework.webflow.execution.FlowSession;
@@ -41,6 +44,11 @@ import org.springframework.webflow.execution.ViewSelection;
* such as HibernateTemplate or the LocalSessionFactoryBean. If not, Hibernate
* data access code will not participate in the proper transaction.
*
* Note that when accessing service layer methods with Spring manged
* transactions, those transaction should have {@link Propagation#REQUIRED}
* semantics. Anything else defeats the purpose of holding the transaction open
* until the end of the session.
*
* @author Ben Hale
* @since 1.1
*/
@@ -60,10 +68,13 @@ public class HibernateSessionPerConversationListener extends FlowExecutionListen
* conversation scope of this {@link FlowSession}. Since
* {@link #resumed(RequestContext)} will not be called on start of the
* session, this method also binds the session to the thread-local location.
* This behavior will only be exhibited on the root flow in a {@link FlowExecution}.
*/
public void sessionCreated(RequestContext context, FlowSession session) {
Session hibSession = createSession(context);
bindSession(hibSession);
if (session.isRoot()) {
Session hibSession = createSession(context);
bindSession(hibSession);
}
}
/**
@@ -94,13 +105,28 @@ public class HibernateSessionPerConversationListener extends FlowExecutionListen
* <code>Session</code> is closed. Since
* {@link #paused(RequestContext, ViewSelection)} will not be called on the
* ending of this session, this method also unbinds the session from the
* thread-local location.
* thread-local location. This behavior will only be exhibited on the root
* flow in a {@link FlowExecution}.
*/
public void sessionEnded(RequestContext context, FlowSession session, AttributeMap output) {
Session hibSession = (Session) context.getConversationScope().remove(HIBERNATE_SESSION);
hibSession.flush();
if (session.isRoot()) {
Session hibSession = (Session) context.getConversationScope().remove(HIBERNATE_SESSION);
hibSession.flush();
unBindSession(hibSession);
destroySession(hibSession);
}
}
/**
* When an exception is thrown from a {@link FlowExecution}, the
* conversationally scoped <code>Session</code> is unbound from the
* thread-local location and the transaction is committed. The
* transaction that is closed is a Hibernate transaction and with a
* FlushMode of MANUAL will not flush anything to the database.
*/
public void exceptionThrown(RequestContext context, FlowExecutionException exception) {
Session hibSession = getHibernateSession(context);
unBindSession(hibSession);
destroySession(hibSession);
}
private Session createSession(RequestContext context) {
@@ -119,8 +145,9 @@ public class HibernateSessionPerConversationListener extends FlowExecutionListen
}
private void bindSession(Session hibSession) {
hibSession.beginTransaction();
Transaction hibTx = hibSession.beginTransaction();
SessionHolder sessionHolder = new SessionHolder(hibSession);
sessionHolder.setTransaction(hibTx);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
}