org.hibernate.connection包分析--DriverManagerConnectionProvider,DatasourceConnectionProvider,UserSuppliedConnectionProvider 类分析

//$Id: DriverManagerConnectionProvider.java 7888 2005-08-12 21:22:38Z oneovthafew $

package org.hibernate.connection;



import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.Properties;



import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.hibernate.HibernateException;

import org.hibernate.cfg.Environment;

import org.hibernate.util.PropertiesHelper;

import org.hibernate.util.ReflectHelper;



/**

 * A connection provider that uses <tt>java.sql.DriverManager</tt>. This provider

 * also implements a very rudimentary connection pool.

 * @see ConnectionProvider

 * @author Gavin King

 */

public class DriverManagerConnectionProvider implements ConnectionProvider {



	private String url;

	private Properties connectionProps;

	private Integer isolation;

	private final ArrayList pool = new ArrayList();

	private int poolSize;

	private int checkedOut = 0;

	private boolean autocommit;



	private static final Logger log = LoggerFactory.getLogger(DriverManagerConnectionProvider.class);



	public void configure(Properties props) throws HibernateException {



		String driverClass = props.getProperty(Environment.DRIVER);



		poolSize = PropertiesHelper.getInt(Environment.POOL_SIZE, props, 20); //default pool size 20

		log.info("Using Hibernate built-in connection pool (not for production use!)");

		log.info("Hibernate connection pool size: " + poolSize);

		

		autocommit = PropertiesHelper.getBoolean(Environment.AUTOCOMMIT, props);

		log.info("autocommit mode: " + autocommit);



		isolation = PropertiesHelper.getInteger(Environment.ISOLATION, props);

		if (isolation!=null)

		log.info( "JDBC isolation level: " + Environment.isolationLevelToString( isolation.intValue() ) );



		if (driverClass==null) {

			log.warn("no JDBC Driver class was specified by property " + Environment.DRIVER);

		}

		else {

			try {

				// trying via forName() first to be as close to DriverManager's semantics

				Class.forName(driverClass);

			}

			catch (ClassNotFoundException cnfe) {

				try {

					ReflectHelper.classForName(driverClass);

				}

				catch (ClassNotFoundException e) {

					String msg = "JDBC Driver class not found: " + driverClass;

					log.error( msg, e );

					throw new HibernateException(msg, e);

				}

			}

		}



		url = props.getProperty( Environment.URL );

		if ( url == null ) {

			String msg = "JDBC URL was not specified by property " + Environment.URL;

			log.error( msg );

			throw new HibernateException( msg );

		}



		connectionProps = ConnectionProviderFactory.getConnectionProperties( props );



		log.info( "using driver: " + driverClass + " at URL: " + url );

		// if debug level is enabled, then log the password, otherwise mask it

		if ( log.isDebugEnabled() ) {

			log.info( "connection properties: " + connectionProps );

		} 

		else if ( log.isInfoEnabled() ) {

			log.info( "connection properties: " + PropertiesHelper.maskOut(connectionProps, "password") );

		}



	}



	public Connection getConnection() throws SQLException {



		if ( log.isTraceEnabled() ) log.trace( "total checked-out connections: " + checkedOut );



		synchronized (pool) {

			if ( !pool.isEmpty() ) {

				int last = pool.size() - 1;

				if ( log.isTraceEnabled() ) {

					log.trace("using pooled JDBC connection, pool size: " + last);

					checkedOut++;

				}

				Connection pooled = (Connection) pool.remove(last);

				if (isolation!=null) pooled.setTransactionIsolation( isolation.intValue() );

				if ( pooled.getAutoCommit()!=autocommit ) pooled.setAutoCommit(autocommit);

				return pooled;

			}

		}



		log.debug("opening new JDBC connection");

		Connection conn = DriverManager.getConnection(url, connectionProps);

		if (isolation!=null) conn.setTransactionIsolation( isolation.intValue() );

		if ( conn.getAutoCommit()!=autocommit ) conn.setAutoCommit(autocommit);



		if ( log.isDebugEnabled() ) {

			log.debug( "created connection to: " + url + ", Isolation Level: " + conn.getTransactionIsolation() );

		}

		if ( log.isTraceEnabled() ) checkedOut++;



		return conn;

	}



	public void closeConnection(Connection conn) throws SQLException {



		if ( log.isDebugEnabled() ) checkedOut--;



		synchronized (pool) {

			int currentSize = pool.size();

			if ( currentSize < poolSize ) {

				if ( log.isTraceEnabled() ) log.trace("returning connection to pool, pool size: " + (currentSize + 1) );

				pool.add(conn);

				return;

			}

		}



		log.debug("closing JDBC connection");



		conn.close();



	}



	protected void finalize() {

		close();

	}



	public void close() {



		log.info("cleaning up connection pool: " + url);



		Iterator iter = pool.iterator();

		while ( iter.hasNext() ) {

			try {

				( (Connection) iter.next() ).close();

			}

			catch (SQLException sqle) {

				log.warn("problem closing pooled connection", sqle);

			}

		}

		pool.clear();



	}



	/**

	 * @see ConnectionProvider#supportsAggressiveRelease()

	 */

	public boolean supportsAggressiveRelease() {

		return false;

	}



}
 

DriverManagerConnectionProvider类继承了ConnectionProvider接口,主要是使用用户提供的JDBC驱动程序来连接数据库,或者使用连接池的方式来连接数据库。    一个典型的JDBC驱动连接数据库的方式:

 <property name="connection.driver_class">com.mysql.jdbc.Driver</property>





<!-- 连接数据库的URL-->



<property name="connection.url"> 



jdbc:mysql://localhost:3306/schoolproject



</property>



<property name="connection.useUnicode">true</property>



<property name="connection.characterEncoding">UTF-8</property>





<!--连接的登录名-->



<property name="connection.username">root</property>





<!—登录密码-->



<property name="connection.password"></property>





<!--是否将运行期生成的SQL输出到日志以供调试-->



<property name="show_sql">true</property>





<!--指定连接的语言-->



<property name="dialect">org.hibernate.dialect.MySQLDialect</property>

 至于连接池,由于在hibernate3.0中,已经不再支持dbcp了,hibernate的作者在hibernate.org中,明确指出在实践中发现dbcp有BUG,在某些种情会产生很多空连接不能释放,所以抛弃了对dbcp的支持。因此官方推荐使用c3p0或Proxool连接池。

  C3P0连接配置

<!—JDBC驱动程序-->



<property name="connection.driver_class">com.mysql.jdbc.Driver</property>



<!-- 连接数据库的URL-->



<property name="connection.url"> 



jdbc:mysql://localhost:3306/schoolproject



</property>



<property name="connection.useUnicode">true</property>



<property name="connection.characterEncoding">UTF-8</property>



<!--连接的登录名-->



<property name="connection.username">root</property>



<!--登录密码-->



<property name="connection.password"></property>



<!-- C3P0连接池设定-->



<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider

</property>



<property name="hibernate.c3p0.max_size">20</property>



<property name="hibernate.c3p0.min_size">5</property>



<property name="hibernate.c3p0.timeout">120</property>



<property name="hibernate.c3p0.max_statements">100</property>



<property name="hibernate.c3p0.idle_test_period">120</property>



<property name="hibernate.c3p0.acquire_increment">2</property>



<!--是否将运行期生成的SQL输出到日志以供调试-->



<property name="show_sql">true</property>



<!--指定连接的语言-->



<property name="dialect">org.hibernate.dialect.MySQLDialect</property>

   首先看DriverManagerConnectionProvider的configure(Properties props)方法,在这个方法中并没有去判断是否使用了连接池,真正判断使用连接池是在ConnectionProviderFactory这个类中,我们以后会分析。   

  DriverManagerConnectionProvider这个类只是初始化了最基本的连接配置,有如下几个:hibernate.connection.driver_class(JDBC驱动类)、hibernate.connection.pool_size(连接池容量的上限数目)、hibernate.connection.autocommit(允许被缓存的JDBC连接开启自动自动提交)、hibernate.connection.isolation(设置JDBC事务隔离级别,可查看java.sql.Connection来了解各个值的具体意义,但请注意多数数据库都不支持所有的隔离级别,取值1,2,4,8)。无论你是使用JDBC还是使用连接池方式,这几个最基本的设置都是要先初始化的。其中pool_size的默认值为20。

  configure(Properties props)方法中的这个语句connectionProps = ConnectionProviderFactory.getConnectionProperties( props );值得注意, ConnectionProviderFactory.getConnectionProperties( props )主要是把HIBERNATE.CFG或者HIBERNATE.PROPERTIES的配置文件中的属性重新封装到另一个Properties 类——connectionProps中,且connectionProps的键值与 HIBERNATE.CFG或者HIBERNATE.PROPERTIES中的键值相比是没有“hibernate.connection”这样的字样的,比如,在HIBERNATE.PROPERTIES中定义的“hibernate.connection.pool_size”属性键,到该Properties 类 中的键就成了“pool_size ”。connectionProps主要是为后面的getConnection()方法而提供的。   

  接下来是getConnection()方法,在这里我们发现了synchronized关键字,这个关键字是加在pool这个对象上的,也就是说某个时刻只有其中的一个线程可以访问这个对象的synchronized数据。每个对象都有一个"锁标志",当这个对象的一个线程访问这个对象的某个synchronized数据时,这个对象的所有被synchronized修饰的数据将被上锁(因为"锁标志"被当前线程拿走了),只有当前线程访问完它要访问的synchronized数据时,当前线程才会释放"锁标志",这样同一个对象的其它线程才有机会访问synchronized数据。pool是什么?它是一个ArrayList,也就是连接池,里面都是一个个的Connection对象,这个可以在后面的closeConnection(Connection conn)体现出来,正在pool上加synchronized修饰符就保证了多个线程不能并发访问此ArrayList而生成不正确的结果。当调用getConnection()方法时,我们可以看到连接池就移除了一个连接。

  Connection conn = DriverManager.getConnection(url, connectionProps)语句中我们可以看到全局变量connectionProps是传入到了这个方法中的,返回了一个Connection 对象。   

   closeConnection(Connection conn)方法是将连接重新放回到连接池。   

  close()方法清空了连接池,关闭所有连接。   

  supportsAggressiveRelease()方法返回的是false,表示连接释放模式会被设置为hibernate.connection.release_mode.AFTER_TRANSACTION也就是说在org.hibernate.Transaction结束后释放连接。

DatasourceConnectionProvider类分析    DatasourceConnectionProvider类比较简单,不同的是,它通过JNDI的方式来查找数据源来获得连接,这个类中要注意的方法是supportsAggressiveRelease()它返回的是true,表示在使用数据源连接的情况下,支持使用hibernate.connection.release_mode.AFTER_STATEMENT这一个设置。

UserSuppliedConnectionProvider类分析    UserSuppliedConnectionProvider 这个类是留给用户自己扩展的,基本上什么都不干。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值