connectionmanager.java

来自「hibernate-3.0.5 中文文档」· Java 代码 · 共 385 行

JAVA
385
字号
// $Id: ConnectionManager.java,v 1.6 2005/05/24 14:31:39 oneovthafew Exp $package org.hibernate.jdbc;import org.hibernate.ConnectionReleaseMode;import org.hibernate.HibernateException;import org.hibernate.engine.SessionFactoryImplementor;import org.hibernate.exception.JDBCExceptionHelper;import org.hibernate.util.JDBCExceptionReporter;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import java.sql.Connection;import java.sql.SQLException;import java.io.Serializable;import java.io.ObjectInputStream;import java.io.IOException;import java.io.ObjectOutputStream;/** * Encapsulates JDBC Connection management logic needed by Hibernate. * <p/> * The lifecycle is intended to span a logical series of interactions with the * database.  Internally, this means the the lifecycle of the Session. * * @author Steve Ebersole */public class ConnectionManager implements Serializable {	// TODO : would love to remove dependence on SF here, and make this a general purpose thing.	//  The SF is only really needed to "pass along" to batcher.	//  Everything we obtain here from factory can (and was) passed in directly.	private static final Log log = LogFactory.getLog( ConnectionManager.class );	public static interface Callback {		public void connectionOpened();		public void connectionCleanedUp();	}	private transient SessionFactoryImplementor factory;	private final Callback callback;	private final ConnectionReleaseMode releaseMode;	private transient Connection connection;	private final boolean wasConnectionSupplied;	private transient boolean shouldObtainConnection;	private transient Batcher batcher; 	/**	 * Constructs a ConnectionManager.	 * <p/>	 * This is the form used internally.	 * 	 * @param factory The SessionFactory.	 * @param callback An observer for internal state change.	 * @param releaseMode The mode by which to release JDBC connections.	 * @param connection An externally supplied connection.	 */ 	public ConnectionManager(	        SessionFactoryImplementor factory,	        Callback callback,	        ConnectionReleaseMode releaseMode,	        Connection connection) {		this.factory = factory;		this.callback = callback;		this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this );		this.releaseMode = releaseMode;		this.connection = connection;		wasConnectionSupplied = ( connection != null );		shouldObtainConnection = !wasConnectionSupplied;	}	/**	 * The session factory.	 *	 * @return the session factory.	 */	public SessionFactoryImplementor getFactory() {		return factory;	}	/**	 * The batcher managed by this ConnectionManager.	 *	 * @return The batcher.	 */	public Batcher getBatcher() {		return batcher;	}	/**	 * Retreives the connection currently managed by this ConnectionManager.	 * <p/>	 * Note, that we may need to obtain a connection to return here if a	 * connection has either not yet been obtained (non-UserSuppliedConnectionProvider)	 * or has previously been aggressively released (if supported in this environment).	 *	 * @return The current Connection.	 *	 * @throws HibernateException Indicates a connection is currently not	 * available (we are currently manually disconnected).	 */	public Connection getConnection() throws HibernateException {		if ( connection == null ) {			if ( shouldObtainConnection ) {				openConnection();			}			else {				throw new HibernateException( "Not able to obtain connection" );			}		}		return connection;	}	/**	 * Is the connection considered "auto-commit"?	 *	 * @return True if we either do not have a connection, or the connection	 * really is in auto-commit mode.	 *	 * @throws SQLException Can be thrown by the Connection.isAutoCommit() check.	 */	public boolean isAutoCommit() throws SQLException {		return connection == null || connection.getAutoCommit();	}	/**	 * Is this ConnectionManager instance "logically" connected.  Meaning	 * do we either have a cached connection available or do we have the	 * ability to obtain a connection on demand.	 *	 * @return True if logically connected; false otherwise.	 */	public boolean isLogicallyConnected() {		return connection != null || shouldObtainConnection;	}	/**	 * Is theis ConnectionManager instance "physically" connection.  Meaning	 * do have currently actually have a cached connection.	 *	 * @return True if physically connected; false otherwise.	 */	public boolean isPhysicallyConnected() {		return connection != null;	}	/**	 * To be called after execution of each JDBC statement.  Used to	 * conditionally release the JDBC connection aggressively if	 * the configured release mode indicates.	 */	public void afterStatement() {		if ( releaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {			if ( batcher.hasOpenResources() ) {				log.info( "Skipping aggresive-release due to open resources on batcher" );			}			else {				aggressiveRelease();			}		}	}	/**	 * To be called after local transaction completion.  Used to conditionally	 * release the JDBC connection aggressivley if the configured release mode	 * indicates.	 */	public void afterTransaction() {		if ( releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ) {			// TODO : also consider the case where after_statement did not release due to open resources;			//      do we want to close eveything here?			aggressiveRelease();		}	}	/**	 * To be called after Session completion.  Used to release the JDBC	 * connection.	 *	 * @return The connection mantained here at time of close.  Null if	 * there was no connection cached internally.	 */	public Connection close() {		if ( connection==null ) {			shouldObtainConnection = false;			return null;		}		else {			return cleanup();		}	}	/**	 * Manually disconnect the underlying JDBC Connection.  The assumption here	 * is that the manager will be reconnected at a later point in time.	 *	 * @return The connection mantained here at time of disconnect.  Null if	 * there was no connection cached internally.	 */	public Connection manualDisconnect() {		return cleanup();	}	/**	 * Manually reconnect the underlying JDBC Connection.  Should be called at	 * some point after manualDisconnect().	 * <p/>	 * This form is used for ConnectionProvider-supplied connections.	 */	public void manualReconnect() {		if ( isLogicallyConnected() ) {			throw new HibernateException( "Already connected" );		}		shouldObtainConnection = true;	}	/**	 * Manually reconnect the underlying JDBC Connection.  Should be called at	 * some point after manualDisconnect().	 * <p/>	 * This form is used for user-supplied connections.	 */	public void manualReconnect(Connection suppliedConnection) {		if ( isLogicallyConnected() ) {			throw new HibernateException( "Already connected" );		}		this.connection = suppliedConnection;	}	/**	 * Releases the Connection and cleans up any resources associated with	 * that Connection.  This leaves the internal state such that a Connection	 * cannot be re-obtained.  This is intended for use:	 * 1) at the end of the session	 * 2) on a manual disconnect of the session	 *	 * @return The released connection.	 * @throws HibernateException	 */	private Connection cleanup() throws HibernateException {		try {			if ( shouldObtainConnection ) {				// the connection was previously released; nothing to do...				shouldObtainConnection = false;				return null;			}			else {				if (connection==null) {					throw new HibernateException( "Already disconnected" );				}				batcher.closeStatements();				Connection c = null;				if ( !wasConnectionSupplied ) {					closeConnection();				}				else {					c = connection;				}				connection = null;				return c;			}		}		finally {			callback.connectionCleanedUp();		}	}	/**	 * Performs actions required to perform an aggressive release of the	 * JDBC Connection.	 */	private void aggressiveRelease() {		if ( !wasConnectionSupplied ) {			log.debug( "aggressively releasing JDBC connection" );			if ( connection != null ) {				closeConnection();			}			shouldObtainConnection = true;		}	}	/**	 * Pysically opens a JDBC Connection.	 *	 * @throws HibernateException	 */	private void openConnection() throws HibernateException {		log.debug("opening JDBC connection");		try {			connection = factory.getConnectionProvider().getConnection();		}		catch (SQLException sqle) {			throw JDBCExceptionHelper.convert(					factory.getSQLExceptionConverter(),					sqle,					"Cannot open connection"			);		}		shouldObtainConnection = false;		callback.connectionOpened(); // register synch; stats.connect()	}	/**	 * Physically closes the JDBC Connection.	 */	private void closeConnection() {		if ( log.isDebugEnabled() ) {			log.debug(					"closing JDBC connection [" +					batcher.openResourceStatsAsString() + "]"			);		}		try {			if ( !connection.isClosed() ) {				JDBCExceptionReporter.logAndClearWarnings( connection );			}			factory.getConnectionProvider().closeConnection( connection );			connection = null;		}		catch (SQLException sqle) {			throw JDBCExceptionHelper.convert( factory.getSQLExceptionConverter(), sqle, "Cannot close connection" );		}	}	/**	 * Used during serialization.	 *	 * @param oos The stream to which we are being written.	 * @throws IOException Indicates an I/O error writing to the stream	 */	private void writeObject(ObjectOutputStream oos) throws IOException {		if ( isPhysicallyConnected() ) {			throw new IllegalStateException( "Cannot serialize a ConnectionManager while connected" );		}		oos.writeObject( factory );		oos.defaultWriteObject();	}	/**	 * Used during deserialization.	 *	 * @param ois The stream from which we are being read.	 * @throws IOException Indicates an I/O error reading the stream	 * @throws ClassNotFoundException Indicates resource class resolution.	 */	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {		factory = ( SessionFactoryImplementor ) ois.readObject();		ois.defaultReadObject();		this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this );	}	/**	 * Just in case user forgot to commit()/cancel() or close()	 */	protected void finalize() throws Throwable {		log.debug( "running Session.finalize()" );		if ( connection != null ) {			if ( connection.isClosed() ) {				log.warn( "finalizing with closed connection" );			}			else {				log.warn("unclosed connection, forgot to call close() on your session?");				// TODO : Should we also call batcher.closeStatements() from here?				if ( !wasConnectionSupplied ) {					connection.close();				}			}		}	}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?