qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          從源代碼解讀hibernate之數據庫連接

           大家都知道hibernate是在JDBC基礎上的封裝,那么它的數據庫連接是怎樣實現的呢?帶著這個疑問最近研究了下hibernate的源代碼,代碼還是比較簡單的,但是做的很通用,好現在一起來看下源代碼

            hibernate的數據庫連接類都放在org.hibernate.connection包內,對于數據庫連接類hibernate稱其為ConnectionProvider,對!就是連接提供者,org.hibernate.connection.ConnectionProvider只是個供hibernate使用的接口,通過該接口的getConnection()方法獲得數據庫連接,但是這個接口到底是怎么樣實現的,或者是由誰提供的,hibernate并不關心,用戶在使用hibernate的時候可以在其配置文件中指定具體的實現類(hoho,這就是面向接口編程的好處),現在看看這個接口的規范:

          package org.hibernate.connection;
          public interface ConnectionProvider {
          /** 初始化建立數據庫連接所需要的配置 */
          public void configure(Properties props) throws HibernateException;
          /** 獲得數據庫連接 */
          public Connection getConnection() throws SQLException;
          /** 關閉數據庫連接 */
          public void closeConnection(Connection conn) throws SQLException;
          /** 釋放連接提供者占用的所有資源 */
          public void close() throws HibernateException;
          }

            接下來要說的是org.hibernate.connection.ConnectionProviderFactory,望名會意,就是制造連接提供者的工廠,這個工廠類里面通過hibernate的配置反射獲得具體的ConnectionProvider實現類的實例

          ConnectionProvider connections;
          String providerClass = properties.getProperty(Environment.CONNECTION_PROVIDER);
          if ( providerClass!=null ) {
          try {
          log.info("Initializing connection provider: " + providerClass);
          //反射獲得具體的ConnectionProvider實現類的實例
          connections = (ConnectionProvider) ReflectHelper.classForName(providerClass).newInstance();
          }
          catch ( Exception e ) {
          log.error( "Could not instantiate connection provider", e );
          throw new HibernateException("Could not instantiate connection provider: " + providerClass);
          }
          }
          else if ( properties.getProperty(Environment.DATASOURCE)!=null ) {
          connections = new DatasourceConnectionProvider();
          }
          else if ( properties.getProperty(Environment.URL)!=null ) {
          connections = new DriverManagerConnectionProvider();
          }
          else {
          connections = new UserSuppliedConnectionProvider();
          }
          ...
          return connections;

          對于ConnectionProvider接口,hibernate自己提供了一套豐富的實現

            1. DatasourceConnectionProvider,這是基于WEB容器提供的JNDI數據庫連接池的連接實現

          package org.hibernate.connection;
          public class DatasourceConnectionProvider implements ConnectionProvider {
          private DataSource ds;
          public void configure(Properties props) throws HibernateException {
          String jndiName = props.getProperty( Environment.DATASOURCE );
          if ( jndiName == null ) {
          String msg = "datasource JNDI name was not specified by property " + Environment.DATASOURCE;
          log.error( msg );
          throw new HibernateException( msg );
          }
          user = props.getProperty( Environment.USER );
          pass = props.getProperty( Environment.PASS );
          try {
          //通過JNDI方式獲得DataSource
          ds = ( DataSource ) NamingHelper.getInitialContext( props ).lookup( jndiName );
          }
          catch ( Exception e ) {
          log.error( "Could not find datasource: " + jndiName, e );
          throw new HibernateException( "Could not find datasource", e );
          }
          if ( ds == null ) {
          throw new HibernateException( "Could not find datasource: " + jndiName );
          }
          log.info( "Using datasource: " + jndiName );
          }
          public Connection getConnection() throws SQLException {
          if (user != null || pass != null) {
          //獲得連接
          return ds.getConnection(user, pass);
          }
          else {
          //獲得連接
          return ds.getConnection();
          }
          }
          }

            2. DriverManagerConnectionProvider,這是基于JDBC的數據庫連接,當然同時也實現了自己的數據庫連接緩存池

          package org.hibernate.connection;
          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);
          //數據庫連接池的大小,默認是20個
          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");
          //如果連接池里沒有空閑的連接,則新建一個JDBC連接并返回
          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();
          }
          /** 釋放連接池 */
          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();
          }
          }

          3. 基于第三方項目的連接池實現,大家可以自己去看hibernate源代碼:org.hibernate.connection.C3P0ConnectionProvider,以及org.hibernate.connection.ProxoolConnectionProvider。

            對于hibernate的普通使用,如下代碼:

          SessionFactory sf = new Configuration().configure().buildSessionFactory();
          Session session = sf.openSession();

            每次openSession()獲得一個session就建立了一條數據庫連接,一個session其實就對應著一條連接

            如果是使用spring和hibernate進行web開發,可能你會用到下面的代碼

          Session session = org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(sessionFactory, true); 

            可以自己去看spring的源代碼,這個返回的Session對象其實已經被包裝后緩存到了ThreadLocal對象里

          posted on 2013-08-12 09:51 順其自然EVO 閱讀(475) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2013年8月>
          28293031123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 隆子县| 平谷区| 肃宁县| 宜良县| 新营市| 斗六市| 怀宁县| 武山县| 惠东县| 宁南县| 古丈县| 甘洛县| 蒲城县| 新和县| 明星| 观塘区| 进贤县| 龙游县| 甘南县| 叶城县| 莲花县| 迁安市| 义乌市| 元朗区| 收藏| 天台县| 安达市| 博客| 沭阳县| 正蓝旗| 新昌县| 麻栗坡县| 夏津县| 吐鲁番市| 新安县| 清徐县| 绥芬河市| 新余市| 黄石市| 化州市| 凤山市|