zoukankan      html  css  js  c++  java
  • 从源代码解读hibernate之数据库连接

    转载 http://cuishen.iteye.com/blog/427921 
    大家都知道hibernate是在JDBC基础上的封装,那么它的数据库连接是怎样实现的呢?带着这个疑问最近研究了下hibernate的源代码,代码还是比较简单的,但是做的很通用,好现在一起来看下源代码 


    hibernate的数据库连接类都放在org.hibernate.connection包内,对于数据库连接类hibernate称其为ConnectionProvider,对!就是连接提供者,org.hibernate.connection.ConnectionProvider只是个供hibernate使用的接口,通过该接口的getConnection()方法获得数据库连接,但是这个接口到底是怎么样实现的,或者是由谁提供的,hibernate并不关心,用户在使用hibernate的时候可以在其配置文件中指定具体的实现类(hoho,这就是面向接口编程的好处),现在看看这个接口的规范: 

    Java代码  收藏代码
    1. package org.hibernate.connection;  
    2.   
    3. public interface ConnectionProvider {  
    4.     /** 初始化建立数据库连接所需要的配置 */  
    5.     public void configure(Properties props) throws HibernateException;  
    6.     /** 获得数据库连接 */  
    7.     public Connection getConnection() throws SQLException;  
    8.     /** 关闭数据库连接 */  
    9.     public void closeConnection(Connection conn) throws SQLException;  
    10.     /** 释放连接提供者占用的所有资源 */  
    11.     public void close() throws HibernateException;  
    12. }  


    接下来要说的是org.hibernate.connection.ConnectionProviderFactory,望名会意,就是制造连接提供者的工厂,这个工厂类里面通过hibernate的配置反射获得具体的ConnectionProvider实现类的实例 

    Java代码  收藏代码
    1. ConnectionProvider connections;  
    2. String providerClass = properties.getProperty(Environment.CONNECTION_PROVIDER);  
    3. if ( providerClass!=null ) {  
    4.     try {  
    5.         log.info("Initializing connection provider: " + providerClass);  
    6.         //反射获得具体的ConnectionProvider实现类的实例  
    7.         connections = (ConnectionProvider) ReflectHelper.classForName(providerClass).newInstance();  
    8.     }  
    9.     catch ( Exception e ) {  
    10.         log.error( "Could not instantiate connection provider", e );  
    11.         throw new HibernateException("Could not instantiate connection provider: " + providerClass);  
    12.     }  
    13. }  
    14. else if ( properties.getProperty(Environment.DATASOURCE)!=null ) {  
    15.     connections = new DatasourceConnectionProvider();  
    16. }  
    17. else if ( properties.getProperty(Environment.URL)!=null ) {  
    18.     connections = new DriverManagerConnectionProvider();  
    19. }  
    20. else {  
    21.     connections = new UserSuppliedConnectionProvider();  
    22. }  
    23. ...  
    24. return connections;  


    对于ConnectionProvider接口,hibernate自己提供了一套丰富的实现 

    1. DatasourceConnectionProvider,这是基于WEB容器提供的JNDI数据库连接池的连接实现 

    Java代码  收藏代码
    1. package org.hibernate.connection;  
    2. public class DatasourceConnectionProvider implements ConnectionProvider {  
    3.     private DataSource ds;  
    4.   
    5.     public void configure(Properties props) throws HibernateException {  
    6.   
    7.         String jndiName = props.getProperty( Environment.DATASOURCE );  
    8.         if ( jndiName == null ) {  
    9.             String msg = "datasource JNDI name was not specified by property " + Environment.DATASOURCE;  
    10.             log.error( msg );  
    11.             throw new HibernateException( msg );  
    12.         }  
    13.   
    14.         user = props.getProperty( Environment.USER );  
    15.         pass = props.getProperty( Environment.PASS );  
    16.   
    17.         try {  
    18.             //通过JNDI方式获得DataSource  
    19.             ds = ( DataSource ) NamingHelper.getInitialContext( props ).lookup( jndiName );  
    20.         }  
    21.         catch ( Exception e ) {  
    22.             log.error( "Could not find datasource: " + jndiName, e );  
    23.             throw new HibernateException( "Could not find datasource", e );  
    24.         }  
    25.         if ( ds == null ) {  
    26.             throw new HibernateException( "Could not find datasource: " + jndiName );  
    27.         }  
    28.         log.info( "Using datasource: " + jndiName );  
    29.     }  
    30.   
    31.     public Connection getConnection() throws SQLException {  
    32.         if (user != null || pass != null) {  
    33.             //获得连接  
    34.             return ds.getConnection(user, pass);  
    35.         }  
    36.         else {  
    37.             //获得连接  
    38.             return ds.getConnection();  
    39.         }  
    40.     }  
    41. }  


    2. DriverManagerConnectionProvider,这是基于JDBC的数据库连接,当然同时也实现了自己的数据库连接缓存池 

    Java代码  收藏代码
    1. package org.hibernate.connection;  
    2. public class DriverManagerConnectionProvider implements ConnectionProvider {  
    3.     private String url;  
    4.     private Properties connectionProps;  
    5.     private Integer isolation;  
    6.     private final ArrayList pool = new ArrayList();  
    7.     private int poolSize;  
    8.     private int checkedOut = 0;  
    9.     private boolean autocommit;  
    10.   
    11.     private static final Logger log = LoggerFactory.getLogger(DriverManagerConnectionProvider.class);  
    12.   
    13.     public void configure(Properties props) throws HibernateException {  
    14.   
    15.         String driverClass = props.getProperty(Environment.DRIVER);  
    16.         //数据库连接池的大小,默认是20个  
    17.         poolSize = PropertiesHelper.getInt(Environment.POOL_SIZE, props, 20); //default pool size 20  
    18.         log.info("Using Hibernate built-in connection pool (not for production use!)");  
    19.         log.info("Hibernate connection pool size: " + poolSize);  
    20.           
    21.         autocommit = PropertiesHelper.getBoolean(Environment.AUTOCOMMIT, props);  
    22.         log.info("autocommit mode: " + autocommit);  
    23.   
    24.         isolation = PropertiesHelper.getInteger(Environment.ISOLATION, props);  
    25.         if (isolation!=null)  
    26.         log.info( "JDBC isolation level: " + Environment.isolationLevelToString( isolation.intValue() ) );  
    27.   
    28.         if (driverClass==null) {  
    29.             log.warn("no JDBC Driver class was specified by property " + Environment.DRIVER);  
    30.         }  
    31.         else {  
    32.             try {  
    33.                 // trying via forName() first to be as close to DriverManager's semantics  
    34.                 Class.forName(driverClass);  
    35.             }  
    36.             catch (ClassNotFoundException cnfe) {  
    37.                 try {  
    38.                     ReflectHelper.classForName(driverClass);  
    39.                 }  
    40.                 catch (ClassNotFoundException e) {  
    41.                     String msg = "JDBC Driver class not found: " + driverClass;  
    42.                     log.error( msg, e );  
    43.                     throw new HibernateException(msg, e);  
    44.                 }  
    45.             }  
    46.         }  
    47.   
    48.         url = props.getProperty( Environment.URL );  
    49.         if ( url == null ) {  
    50.             String msg = "JDBC URL was not specified by property " + Environment.URL;  
    51.             log.error( msg );  
    52.             throw new HibernateException( msg );  
    53.         }  
    54.   
    55.         connectionProps = ConnectionProviderFactory.getConnectionProperties( props );  
    56.   
    57.         log.info( "using driver: " + driverClass + " at URL: " + url );  
    58.         // if debug level is enabled, then log the password, otherwise mask it  
    59.         if ( log.isDebugEnabled() ) {  
    60.             log.info( "connection properties: " + connectionProps );  
    61.         }   
    62.         else if ( log.isInfoEnabled() ) {  
    63.             log.info( "connection properties: " + PropertiesHelper.maskOut(connectionProps, "password") );  
    64.         }  
    65.   
    66.     }  
    67.   
    68.     public Connection getConnection() throws SQLException {  
    69.   
    70.         if ( log.isTraceEnabled() ) log.trace( "total checked-out connections: " + checkedOut );  
    71.   
    72.         synchronized (pool) {  
    73.             if ( !pool.isEmpty() ) {  
    74.                 int last = pool.size() - 1;  
    75.                 if ( log.isTraceEnabled() ) {  
    76.                     log.trace("using pooled JDBC connection, pool size: " + last);  
    77.                     checkedOut++;  
    78.                 }  
    79.                 //如果连接池里有空闲的连接,则返回一个连接,并将该连接从连接池里移除  
    80.                 Connection pooled = (Connection) pool.remove(last);  
    81.                 if (isolation!=null) pooled.setTransactionIsolation( isolation.intValue() );  
    82.                 if ( pooled.getAutoCommit()!=autocommit ) pooled.setAutoCommit(autocommit);  
    83.                 return pooled;  
    84.             }  
    85.         }  
    86.   
    87.         log.debug("opening new JDBC connection");  
    88.         //如果连接池里没有空闲的连接,则新建一个JDBC连接并返回  
    89.         Connection conn = DriverManager.getConnection(url, connectionProps);  
    90.         if (isolation!=null) conn.setTransactionIsolation( isolation.intValue() );  
    91.         if ( conn.getAutoCommit()!=autocommit ) conn.setAutoCommit(autocommit);  
    92.   
    93.         if ( log.isDebugEnabled() ) {  
    94.             log.debug( "created connection to: " + url + ", Isolation Level: " + conn.getTransactionIsolation() );  
    95.         }  
    96.         if ( log.isTraceEnabled() ) checkedOut++;  
    97.   
    98.         return conn;  
    99.     }  
    100.   
    101.     public void closeConnection(Connection conn) throws SQLException {  
    102.   
    103.         if ( log.isDebugEnabled() ) checkedOut--;  
    104.   
    105.         synchronized (pool) {  
    106.             int currentSize = pool.size();  
    107.             if ( currentSize < poolSize ) {  
    108.                 if ( log.isTraceEnabled() ) log.trace("returning connection to pool, pool size: " + (currentSize + 1) );  
    109.                 //如果连接池没有满,则将该连接放进连接池  
    110.                 pool.add(conn);  
    111.                 return;  
    112.             }  
    113.         }  
    114.   
    115.         log.debug("closing JDBC connection");  
    116.         //如果连接池已满,则关闭该连接  
    117.         conn.close();  
    118.   
    119.     }  
    120.   
    121.     /** 释放连接池 */  
    122.     public void close() {  
    123.   
    124.         log.info("cleaning up connection pool: " + url);  
    125.   
    126.         Iterator iter = pool.iterator();  
    127.         while ( iter.hasNext() ) {  
    128.             try {  
    129.                 ( (Connection) iter.next() ).close();  
    130.             }  
    131.             catch (SQLException sqle) {  
    132.                 log.warn("problem closing pooled connection", sqle);  
    133.             }  
    134.         }  
    135.         pool.clear();  
    136.   
    137.     }  
    138. }  


    3. 基于第三方项目的连接池实现,大家可以自己去看hibernate源代码:org.hibernate.connection.C3P0ConnectionProvider,以及org.hibernate.connection.ProxoolConnectionProvider。 

    对于hibernate的普通使用,如下代码: 

    Java代码  收藏代码
    1. SessionFactory sf = new Configuration().configure().buildSessionFactory();  
    2. Session session = sf.openSession();  


    每次openSession()获得一个session就建立了一条数据库连接,一个session其实就对应着一条连接 

    如果是使用spring和hibernate进行web开发,可能你会用到下面的代码 

    Java代码  收藏代码
    1. Session session = org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(sessionFactory, true);  


    可以自己去看spring的源代码,这个返回的Session对象其实已经被包装后缓存到了ThreadLocal对象里 
  • 相关阅读:
    Windows 8实例教程系列 开篇
    qt 开发发布于 windeploy.exe
    qt qoci 测试验证
    vmware vmx 版本不兼容
    qt oracle
    vc qt dll
    QOCIDriver unable to create environment
    qoci 编译完 放置位置 具体根据情况
    calling 'lastError' with incomplete return type 'QSqlError' qsqlquer
    Hbase 操作工具类
  • 原文地址:https://www.cnblogs.com/chenying99/p/2709030.html
Copyright © 2011-2022 走看看