`
dylan0514sina.cn
  • 浏览: 94993 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

ConnectionManager 管理JDBC连接

 
阅读更多
log:打印日志(废话)
callback: 回调类:在 打开连接,关闭连接,事务状态时机定义动作
factory:供应ConnectionProvider以提供连接,Batch以管理Statement
releaseMode:释放模式
connection:连接缓存
borrowedConnection:连用连接缓存
wasConnectionSupplied:提供的连接是被客户端提供的而非ConnectionProvider
batcher:管理Statement
interceptor:拦截器,给batcher用
isClosed:该类实例是否关闭
isFlushing:改状态值是为了解决一次flush中发多条Statement时,重复释放连接问题


 可以把session与connection的使用关系分为三种 

  session使用的连接是被提供的,常常SessionFactory.openSession(connection,Interceptor?) 
  session使用的连接被借给客户端,常常session.connection 
  session通过connectionProvider.getConnection得到的连接 
   如果session使用的连接是被提供的,那么当之后调用session.connection向session借取的连接就是之前被提供的连接,这类型的连接释放模式必须是ON_CLOSE,但即使这样,连接也不能由session关闭之后而关闭,既然是被提供的,当然生命周期不必与Session同步 
   如果session使用的连接是通过connectionprovider得到,并被提供给客户端,那么此时的客户端得到的是一个代理连接(被代理的对象正是connectionprovider获取的),当调用代理连接的close方法,并不能关闭被代理的连接,只是标识缓存中的borrowedConnection为空并设置代理连接不可用,因为既然是借用session的,当然不能够擅自了结连接。 
   如果session使用的连接是通过connectionprovider得到,那么连接的释放遵守ConnectionReleaseMode定义
  
  事务&非事务操作
  在hibernate中事务和非事务操作划分原则体现在TransactionFactory.isTransactionInProgress方法上
  对JDBC事务来说,由jdbcTransaction.begin标志事务为激活状态,并且没有提交或回滚,则之后的操作认为是事务性的
  对JTA事务来说,只要检测到事务javax.transaction.Status
=STATUS_ACTIVE或STATUS_MARKED_ROLLBACK(至于由javax.transaction.UserTransaction还是javax.transaction.TransactionManager.getTransaction确定事务状态都无所谓)则之后的操作认为是事务性的
   对CMT事务来说,只能由javax.transaction.TransactionManager.getTransaction确定javax.transaction.Status
=STATUS_ACTIVE或STATUS_MARKED_ROLLBACK,则之后的操作认为是事务性的

   当确定其中一种事务管理后,如果isTransactionInProgress返回false,则之后的操作被认为是事务性操作
   

  释放操作执行

    afterStatement由以下调用操作调用
    flush完成之后
     关闭每条Statement之后
     创建或删除临时表之后

    调用afterStatement并不能保证连接立即关闭,下列条件都必须满足
      releaseMode等于AFTER_STATEMENT或者非事务环境下的自动提交模式
      flush完成之后或没有flush
     由batch管理的Statement和ResultSet全被关闭掉
      连接没被借出去或被借出去之后关闭掉的 
   
   afterTransaction由以下情况调用
     session.close或disconnect(先关闭所有Statement)
     事务提交或回滚之后的同步处理(本地同步或JTA同步)
      非事务环境查询
   afterTransaction中下列条件之一满足即可关闭连接
      releaseMode等于AFTER_TRANSACTION
     releaseMode等于AFTER_STATEMENT并且batch还有未关闭的Statement和ResultSet:同时关闭尚未处理的Statement和ResultSet

// $Id: ConnectionManager.java 11304 2007-03-19 22:06:45Z steve.ebersole@jboss.com $
package org.hibernate.jdbc;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.util.JDBCExceptionReporter;

/**
 * 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 {

	private static final Log log = LogFactory.getLog( ConnectionManager.class );

	public static interface Callback {
		public void connectionOpened();
		public void connectionCleanedUp();
		public boolean isTransactionInProgress();
	}

	private transient SessionFactoryImplementor factory;
	private final Callback callback;

	private final ConnectionReleaseMode releaseMode;
	private transient Connection connection;
	private transient Connection borrowedConnection;

	private final boolean wasConnectionSupplied;
	private transient Batcher batcher;
	private transient Interceptor interceptor;
	private boolean isClosed;
	private transient boolean isFlushing;
 
	/**
	 * 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,
	        Interceptor interceptor) {
		this.factory = factory;
		this.callback = callback;

		this.interceptor = interceptor;
		this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this, interceptor );

		this.connection = connection;
		wasConnectionSupplied = ( connection != null );

		this.releaseMode = wasConnectionSupplied ? ConnectionReleaseMode.ON_CLOSE : releaseMode;
	}

	/**
	 * Private constructor used exclusively from custom serialization
	 */
	private ConnectionManager(
	        SessionFactoryImplementor factory,
	        Callback callback,
	        ConnectionReleaseMode releaseMode,
	        Interceptor interceptor,
	        boolean wasConnectionSupplied,
	        boolean isClosed) {
		this.factory = factory;
		this.callback = callback;

		this.interceptor = interceptor;
		this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this, interceptor );

		this.wasConnectionSupplied = wasConnectionSupplied;
		this.isClosed = isClosed;
		this.releaseMode = wasConnectionSupplied ? ConnectionReleaseMode.ON_CLOSE : releaseMode;
	}

	/**
	 * 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;
	}

	/**
	 * Was the connection being used here supplied by the user?
	 *
	 * @return True if the user supplied the JDBC connection; false otherwise
	 */
	public boolean isSuppliedConnection() {
		return wasConnectionSupplied;
	}

	/**
	 * Retrieves 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 ( isClosed ) {
			throw new HibernateException( "connection manager has been closed" );
		}
		if ( connection == null  ) {
			openConnection();
		}
		return connection;
	}

	public boolean hasBorrowedConnection() {
		// used from testsuite
		return borrowedConnection != null;
	}

	public Connection borrowConnection() {
		if ( isClosed ) {
			throw new HibernateException( "connection manager has been closed" );
		}
		if ( isSuppliedConnection() ) {
			return connection;
		}
		else {
			if ( borrowedConnection == null ) {
				borrowedConnection = BorrowedConnectionProxy.generateProxy( this );
			}
			return borrowedConnection;
		}
	}

	public void releaseBorrowedConnection() {
		if ( borrowedConnection != null ) {
			try {
				BorrowedConnectionProxy.renderUnuseable( borrowedConnection );
			}
			finally {
				borrowedConnection = null;
			}
		}
	}

	/**
	 * 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.isClosed()
			|| connection.getAutoCommit();
	}

	/**
	 * Will connections be released after each statement execution?
	 * <p/>
	 * Connections will be released after each statement if either:<ul>
	 * <li>the defined release-mode is {@link ConnectionReleaseMode#AFTER_STATEMENT}; or
	 * <li>the defined release-mode is {@link ConnectionReleaseMode#AFTER_TRANSACTION} but
	 * we are in auto-commit mode.
	 * <p/>
	 * release-mode = {@link ConnectionReleaseMode#ON_CLOSE} should [b]never[/b] release
	 * a connection.
	 *
	 * @return True if the connections will be released after each statement; false otherwise.
	 */
	public boolean isAggressiveRelease() {
		if ( releaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
			return true;
		}
		else if ( releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ) {
			boolean inAutoCommitState;
			try {
				inAutoCommitState = isAutoCommit()&& !callback.isTransactionInProgress();
			}
			catch( SQLException e ) {
				// assume we are in an auto-commit state
				inAutoCommitState = true;
			}
			return inAutoCommitState;
		}
		return false;
	}

	/**
	 * Modified version of {@link #isAggressiveRelease} which does not force a
	 * transaction check.  This is solely used from our {@link #afterTransaction}
	 * callback, so no need to do the check; plus it seems to cause problems on
	 * websphere (god i love websphere ;)
	 * </p>
	 * It uses this information to decide if an aggressive release was skipped
	 * do to open resources, and if so forces a release.
	 *
	 * @return True if the connections will be released after each statement; false otherwise.
	 */
	private boolean isAggressiveReleaseNoTransactionCheck() {
		if ( releaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
			return true;
		}
		else {
			boolean inAutoCommitState;
			try {
				inAutoCommitState = isAutoCommit();
			}
			catch( SQLException e ) {
				// assume we are in an auto-commit state
				inAutoCommitState = true;
			}
			return releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION && inAutoCommitState;
		}
	}

	/**
	 * 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 isCurrentlyConnected() {
		return wasConnectionSupplied ? connection != null : !isClosed;
	}

	/**
	 * 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 ( isAggressiveRelease() ) {
			if ( isFlushing ) {
				log.debug( "skipping aggressive-release due to flush cycle" );
			}
			else if ( batcher.hasOpenResources() ) {
				log.debug( "skipping aggresive-release due to open resources on batcher" );
			}
			else if ( borrowedConnection != null ) {
				log.debug( "skipping aggresive-release due to borrowed connection" );
			}
			else {
				aggressiveRelease();
			}
		}
	}

	/**
	 * To be called after local transaction completion.  Used to conditionally
	 * release the JDBC connection aggressively if the configured release mode
	 * indicates.
	 */
	public void afterTransaction() {
		if ( isAfterTransactionRelease() ) {
			aggressiveRelease();
		}
		else if ( isAggressiveReleaseNoTransactionCheck() && batcher.hasOpenResources() ) {
			log.info( "forcing batcher resource cleanup on transaction completion; forgot to close ScrollableResults/Iterator?" );
			batcher.closeStatements();
			aggressiveRelease();
		}
		else if ( isOnCloseRelease() ) {
			// log a message about potential connection leaks
			log.debug( "transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!" );
		}
		batcher.unsetTransactionTimeout();
	}

	private boolean isAfterTransactionRelease() {
		return releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION;
	}

	private boolean isOnCloseRelease() {
		return releaseMode == ConnectionReleaseMode.ON_CLOSE;
	}

	/**
	 * 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() {
		try {
			return cleanup();
		}
		finally {
			isClosed = true;
		}
	}

	/**
	 * 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() {
	}

	/**
	 * 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) {
		this.connection = suppliedConnection;
	}

	/**
	 * Releases the Connection and cleans up any resources associated with
	 * that Connection.  This is intended for use:
	 * 1) at the end of the session
	 * 2) on a manual disconnect of the session
	 * 3) from afterTransaction(), in the case of skipped aggressive releasing
	 *
	 * @return The released connection.
	 * @throws HibernateException
	 */
	private Connection cleanup() throws HibernateException {
		releaseBorrowedConnection();

		if ( connection == null ) {
			log.trace( "connection already null in cleanup : no action");
			return null;
		}

		try {
			log.trace( "performing cleanup" );

			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();
			}
		}
	}

	/**
	 * Pysically opens a JDBC Connection.
	 *
	 * @throws HibernateException
	 */
	private void openConnection() throws HibernateException {
		if ( connection != null ) {
			return;
		}

		log.debug("opening JDBC connection");
		try {
			connection = factory.getConnectionProvider().getConnection();
		}
		catch (SQLException sqle) {
			throw JDBCExceptionHelper.convert(
					factory.getSQLExceptionConverter(),
					sqle,
					"Cannot open connection"
				);
		}

		callback.connectionOpened(); // register synch; stats.connect()
	}

	/**
	 * Physically closes the JDBC Connection.
	 */
	private void closeConnection() {
		if ( log.isDebugEnabled() ) {
			log.debug(
					"releasing 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 release connection"
				);
		}
	}

	/**
	 * Callback to let us know that a flush is beginning.  We use this fact
	 * to temporarily circumvent aggressive connection releasing until after
	 * the flush cycle is complete {@link #flushEnding()}
	 */
	public void flushBeginning() {
		log.trace( "registering flush begin" );
		isFlushing = true;
	}

	/**
	 * Callback to let us know that a flush is ending.  We use this fact to
	 * stop circumventing aggressive releasing connections.
	 */
	public void flushEnding() {
		log.trace( "registering flush end" );
		isFlushing = false;
		afterStatement();
	}

	public boolean isReadyForSerialization() {
		return wasConnectionSupplied ? connection == null : !batcher.hasOpenResources();
	}

	/**
	 * 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 ( !isReadyForSerialization() ) {
			throw new IllegalStateException( "Cannot serialize a ConnectionManager while connected" );
		}

		oos.writeObject( factory );
		oos.writeObject( interceptor );
		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();
		interceptor = (Interceptor) ois.readObject();
		ois.defaultReadObject();

		this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this, interceptor );
	}

	public void serialize(ObjectOutputStream oos) throws IOException {
		oos.writeBoolean( wasConnectionSupplied );
		oos.writeBoolean( isClosed );
	}

	public static ConnectionManager deserialize(
			ObjectInputStream ois,
	        SessionFactoryImplementor factory,
	        Interceptor interceptor,
	        ConnectionReleaseMode connectionReleaseMode,
	        JDBCContext jdbcContext) throws IOException {
		return new ConnectionManager(
				factory,
		        jdbcContext,
		        connectionReleaseMode,
		        interceptor,
		        ois.readBoolean(),
		        ois.readBoolean()
		);
	}

}

分享到:
评论

相关推荐

    JDBC数据库连接测试

    JDBC连接数据库 连接数据库通常分为以下步骤: 1. **加载驱动**:使用`Class.forName()`方法加载对应的数据库驱动。 2. **获取连接**:通过`DriverManager.getConnection()`方法,传入数据库URL、用户名和密码来...

    jdbc连接测试项目

    - **驱动管理器(Driver Manager)**:它是JDBC的入口点,负责管理数据库驱动,并建立与数据库的连接。 - **数据库驱动**:每个数据库厂商都会提供对应JDBC的驱动实现,如MySQL的`com.mysql.jdbc.Driver`。 - **...

    JDBC连接数据库里面有各数据库的应用说明

    ### JDBC连接数据库应用详解 #### 一、JDBC概述及DriverManager的作用 JDBC(Java Database Connectivity)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一的访问接口。通过JDBC,Java应用程序...

    jdbc连接池dbcp工具包

    DBCP(Jakarta DBCP,又称为Apache Commons DBCP)是Apache软件基金会提供的一款开源的JDBC连接池实现,它为Java开发者提供了方便、高效的数据库连接管理功能。 DBCP工具包的出现,主要是为了解决频繁创建和销毁...

    eclipes通过JDBC连接SQLServer配置,最新版本

    在本文中,我们将详细探讨如何使用Eclipse通过JDBC连接到SQL Server 2014数据库,基于最新的JDK 1.8环境。首先,确保你的系统已经安装了JDK 1.8和SQL Server 2014,并且启用了SQL Server的身份验证模式。 1. **SQL ...

    在Eclipse中用JDBC连接Sql Server 2005总结

    【在Eclipse中使用JDBC连接SQL Server 2005的步骤详解】 要使用Java的JDBC(Java Database Connectivity)在Eclipse中连接到SQL Server 2005,你需要遵循以下步骤: 1. **准备工作**: - 安装必备软件: - ...

    jdbc连接oracle,执行存储过程,带数据库存储过程

    这个类可能利用上述JDBC连接Oracle和执行存储过程的方法来管理用户信息。 总之,通过JDBC连接Oracle并执行存储过程,开发者可以高效地进行数据库操作,实现复杂的业务逻辑。在实际开发中,还需要注意事务管理、错误...

    JDBC连接Sql Server 2005总结

    在本文中,我们将深入探讨如何使用JDBC连接到SQL Server 2005,以及在这个过程中涉及的一些关键知识点。 首先,确保你已经准备了以下软件: 1. Microsoft SQL Server 2005 Express Edition:这是数据库服务器,...

    JDBC连接MySQL 实例

    **JDBC连接MySQL实例详解** Java Database Connectivity (JDBC) 是Java编程语言中用于与数据库交互的一种接口标准,由Sun Microsystems公司(现为Oracle公司)开发。它为Java程序员提供了标准化的方法来创建、执行...

    JDBC连接数据库架包

    这个"JDBC连接数据库架包"包含了实现这些接口和类的库,使得Java开发者能够方便、高效地访问和操作数据库系统。在Java项目中,导入这样的架包是建立数据库连接的第一步。 首先,我们需要理解JDBC的基本概念。JDBC是...

    Connection Pool Manager:JDBC连接池管理器-开源

    icpool简单易用,连接池管理器。 可以出于任何目的完全免费下载和使用。

    JDBC数据源连接池的配置和使用示例

    - C3P0:开源的JDBC连接池,提供了比JDBC更强大的功能,如自动检测死锁、自动重连等。 - DBCP:Apache的一个开源项目,基于Jakarta-pool实现,是Tomcat默认的数据源。 - HikariCP:被誉为“最快的Java JDBC连接池”...

    在Eclipse中用JDBC连接Sql_Server_2005

    Eclipse 中用 JDBC 连接 Sql_Server_2005 Eclipse 是一个功能强大的集成开发环境(IDE),它支持多种编程语言,包括 Java、C++、Python 等。在本篇文章中,我们将详细介绍如何在 Eclipse 中使用 JDBC 连接 Sql_...

    JDBC连接代码,有得到连接的方法

    在提供的示例代码中,我们看到了一个名为`ConnectionManager`的类,该类主要负责管理与数据库的连接,并通过静态方法`getConn()`返回数据库连接对象。接下来将对代码进行详细解析。 ##### 常量定义 ```java public...

    jdbc连接sql.txt

    ### JDBC 连接 SQL 方法详解 #### 一、JDBC 连接 SQL Server 2000 在早期的数据库环境中,SQL Server 2000 是一个非常流行的选择。对于使用 Java 开发的应用程序来说,通过 JDBC (Java Database Connectivity) ...

    JDBC 连接 sql2005

    在本场景中,我们讨论的是如何使用JDBC连接到SQL Server 2005。以下是一些关键知识点: 1. **JDBC驱动**: - JDBC驱动是Java应用程序与数据库之间的桥梁,它允许Java代码执行SQL语句。对于SQL Server 2005,我们...

    jdbc连接SqlServer

    ### JDBC 连接 Sql Server 2005 在 Eclipse 中的应用 ...通过以上步骤,我们可以在Eclipse环境下成功地使用JDBC连接并操作Microsoft SQL Server 2005数据库。这对于Java开发者来说是一种非常实用且重要的技能。

    用JDBC管理数据库连接

    此外,JDBC连接池也是优化数据库性能的重要手段。通过连接池,可以重复利用已建立的数据库连接,避免频繁创建和销毁连接带来的开销。常见的Java连接池工具有Apache的DBCP、C3P0,以及HikariCP等。 总之,JDBC为Java...

Global site tag (gtag.js) - Google Analytics