org.hibernate.SessionException: Session was already closed org.hibernate.impl.SessionImpl.close(SessionImpl.java:275) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)原本針對Spring package 去trace debug log , 以為是Project 設計上的問題,造成Session 物件reference的錯誤,後來把hibernate package debug log也打開後才發現根本的問題....@$@!%@!%,在網路上查找了一些問題,有些是Lazy load的問題,有些是可以透過opensessioninviewfilter , 或著OpenSessionInViewInterceptor 來解決的問題,但是在trace log 之後發現了一個很根本的問題,也很...蠢的問題。就照字面上的意思, Session 已經被關閉了,當Spring 在HibernateTransactionManager doCommit之後 最後在HibernateTransactionManager 執行doCleanupAfterCompletion , 時會去關閉session ,在這邊產生了Exception , 主要是因為Spring 裡面的ApplicationContext 的設定問題
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" destroy-method="destroy"> <property name="dataSource"> <ref bean="myDatasource" /> </property> <property name="annotatedClasses"> <list> ........... ........... </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.transaction.auto_close_session">false</prop> </props> </property> </bean>
如果把hibernate.transaction.auto_close_session 設為true , 在Transaction 提交的時候會把session close, 兇手就在JDBCTransaction 裡面的closeIfRequired, 然後調用 transactionContext.managedClose() 這邊,下面是Source code
org.hibernate.transaction.JDBCTransaction
package org.hibernate.transaction; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import javax.transaction.Status; import javax.transaction.Synchronization; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.HibernateException; import org.hibernate.Transaction; import org.hibernate.TransactionException; import org.hibernate.jdbc.JDBCContext; /** * Implements a basic transaction strategy for JDBC connections.This is the * default <tt>Transaction</tt> implementation used if none is explicitly * specified. * @author Anton van Straaten, Gavin King */ public class JDBCTransaction implements Transaction { private static final Log log = LogFactory.getLog(JDBCTransaction.class); private final JDBCContext jdbcContext; private final TransactionFactory.Context transactionContext; private boolean toggleAutoCommit; private boolean begun; private boolean rolledBack; private boolean committed; private boolean commitFailed; private List synchronizations; private boolean callback; private int timeout = -1; public JDBCTransaction(JDBCContext jdbcContext, TransactionFactory.Context transactionContext) { this.jdbcContext = jdbcContext; this.transactionContext = transactionContext; } public void begin() throws HibernateException { if (begun) { return; } if (commitFailed) { throw new TransactionException("cannot re-start transaction after failed commit"); } log.debug("begin"); try { toggleAutoCommit = jdbcContext.connection().getAutoCommit(); if ( log.isDebugEnabled() ) { log.debug("current autocommit status: " toggleAutoCommit); } if (toggleAutoCommit) { log.debug("disabling autocommit"); jdbcContext.connection().setAutoCommit(false); } } catch (SQLException e) { log.error("JDBC begin failed", e); throw new TransactionException("JDBC begin failed: ", e); } callback = jdbcContext.registerCallbackIfNecessary(); begun = true; committed = false; rolledBack = false; if ( timeout>0 ) { jdbcContext.getConnectionManager() .getBatcher() .setTransactionTimeout(timeout); } jdbcContext.afterTransactionBegin(this); } private void closeIfRequired() throws HibernateException { if ( callback && transactionContext.shouldAutoClose() && !transactionContext.isClosed() ) { try { transactionContext.managedClose(); } catch (HibernateException he) { log.error("Could not close session", he); //swallow, the transaction was finished } } } public void commit() throws HibernateException { if (!begun) { throw new TransactionException("Transaction not successfully started"); } log.debug("commit"); if ( !transactionContext.isFlushModeNever() && callback ) { transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback() } notifyLocalSynchsBeforeTransactionCompletion(); if ( callback ) { jdbcContext.beforeTransactionCompletion( this ); } try { commitAndResetAutoCommit(); log.debug("committed JDBC Connection"); committed = true; if ( callback ) { jdbcContext.afterTransactionCompletion( true, this ); } notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_COMMITTED ); } catch (SQLException e) { log.error("JDBC commit failed", e); commitFailed = true; if ( callback ) { jdbcContext.afterTransactionCompletion( false, this ); } notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_UNKNOWN ); throw new TransactionException("JDBC commit failed", e); } finally { closeIfRequired(); } } private void commitAndResetAutoCommit() throws SQLException { try { jdbcContext.connection().commit(); } finally { toggleAutoCommit(); } } public void rollback() throws HibernateException { if (!begun && !commitFailed) { throw new TransactionException("Transaction not successfully started"); } log.debug("rollback"); if (!commitFailed) { /*notifyLocalSynchsBeforeTransactionCompletion(); if ( callback ) { jdbcContext.notifyLocalSynchsBeforeTransactionCompletion( this ); }*/ try { rollbackAndResetAutoCommit(); log.debug("rolled back JDBC Connection"); rolledBack = true; notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_ROLLEDBACK); } catch (SQLException e) { log.error("JDBC rollback failed", e); notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_UNKNOWN); throw new TransactionException("JDBC rollback failed", e); } finally { if ( callback ) { jdbcContext.afterTransactionCompletion( false, this ); } closeIfRequired(); } } } private void rollbackAndResetAutoCommit() throws SQLException { try { jdbcContext.connection().rollback(); } finally { toggleAutoCommit(); } } private void toggleAutoCommit() { try { if (toggleAutoCommit) { log.debug("re-enabling autocommit"); jdbcContext.connection().setAutoCommit( true ); } } catch (Exception sqle) { log.error("Could not toggle autocommit", sqle); //swallow it (the transaction _was_ successful or successfully rolled back) } } public boolean wasRolledBack() { return rolledBack; } public boolean wasCommitted() { return committed; } public boolean isActive() { return begun && ! ( rolledBack || committed | commitFailed ); } public void registerSynchronization(Synchronization sync) throws HibernateException { if (sync==null) throw new NullPointerException("null Synchronization"); if (synchronizations==null) { synchronizations = new ArrayList(); } synchronizations.add(sync); } private void notifyLocalSynchsBeforeTransactionCompletion() { if (synchronizations!=null) { for ( int i=0; i<synchronizations.size(); i ) { Synchronization sync = (Synchronization) synchronizations.get(i); try { sync.beforeCompletion(); } catch (Throwable t) { log.error("exception calling user Synchronization", t); } } } } private void notifyLocalSynchsAfterTransactionCompletion(int status) { begun = false; if (synchronizations!=null) { for ( int i=0; i<synchronizations.size(); i ) { Synchronization sync = (Synchronization) synchronizations.get(i); try { sync.afterCompletion(status); } catch (Throwable t) { log.error("exception calling user Synchronization", t); } } } } public void setTimeout(int seconds) { timeout = seconds; } }
下面是完整的Transaction complete log
2011/05/16 14:33:12 [DEBUG] TransactionAspectSupport.java/commitTransactionAfterReturning:319, Completing transaction for [com.gfactor.emaildiscovery.service.NewCaseService.getAllCaseInfoByUser] 2011/05/16 14:33:12 [DEBUG] AbstractPlatformTransactionManager.java/triggerBeforeCommit:903, Triggering beforeCommit synchronization 2011/05/16 14:33:12 [DEBUG] AbstractPlatformTransactionManager.java/triggerBeforeCompletion:916, Triggering beforeCompletion synchronization 2011/05/16 14:33:12 [DEBUG] AbstractPlatformTransactionManager.java/processCommit:730, Initiating transaction commit 2011/05/16 14:33:12 [DEBUG] HibernateTransactionManager.java/doCommit:651, Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@1652b8b] 2011/05/16 14:33:12 [DEBUG] JDBCTransaction.java/commit:103, commit 2011/05/16 14:33:12 [DEBUG] JDBCTransaction.java/toggleAutoCommit:193, re-enabling autocommit 2011/05/16 14:33:12 [DEBUG] JDBCTransaction.java/commit:116, committed JDBC Connection 2011/05/16 14:33:12 [DEBUG] AbstractPlatformTransactionManager.java/triggerAfterCommit:929, Triggering afterCommit synchronization 2011/05/16 14:33:12 [DEBUG] AbstractPlatformTransactionManager.java/triggerAfterCompletion:945, Triggering afterCompletion synchronization 2011/05/16 14:33:12 [DEBUG] TransactionSynchronizationManager.java/clearSynchronization:315, Clearing transaction synchronization 2011/05/16 14:33:12 [DEBUG] TransactionSynchronizationManager.java/doUnbindResource:232, Removed value [org.springframework.orm.hibernate3.SessionHolder@461b58] for key [org.hibernate.impl.SessionFactoryImpl@f8f332] from thread [http-8080-2] 2011/05/16 14:33:12 [DEBUG] TransactionSynchronizationManager.java/doUnbindResource:232, Removed value [org.springframework.jdbc.datasource.ConnectionHolder@10dc9f5] for key [org.apache.tomcat.dbcp.dbcp.BasicDataSource@1fb24d3] from thread [http-8080-2] 2011/05/16 14:33:12 [DEBUG] HibernateTransactionManager.java/doCleanupAfterCompletion:730, Closing Hibernate Session [org.hibernate.impl.SessionImpl@1652b8b] after transaction 2011/05/16 14:33:12 [DEBUG] SessionFactoryUtils.java/closeSession:789, Closing Hibernate Session
沒有留言:
張貼留言