org.hibernate.connection包分析--DriverManagerConnectionProvider,DatasourceConnect
view plaincopy to clipboardprint?
- //$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驱动连接数据库的方式:
view plaincopy to clipboardprint?- ?<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连接配置
view plaincopy to clipboardprint?- <!—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 这个类是留给用户自己扩展的,基本上什么都不干。