zoukankan      html  css  js  c++  java
  • PooledDataSource类

    PooledDataSource主要涉及到两个类PooledConnection以及PoolState
    PooledConnection:PooledDataSource中创建的数据库连接,可以获得实际的realConnection和proxyConnection链接对象,重点说明PooledConnection实现了InvocationHandler(即实现Aop时用到的一种动态代理)接口
    PoolState:与PooledDataSource对应,记录数据源对应连接池的状态,包括空闲、活动链接数量,以及连接池的统计信息。
    PooledConnection下的属性说明;
    Connection realConnection:真正的 用于连接数据库的连接,即各个JDBC封装后的Connection,例如org.hsqldb.jdbc.JDBCConnection实现的JDBC
     
    Connection proxyConnection:通过动态代理获得的连接,
    this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);
     
    下面主要介绍PooledDataSource类中的方法:
    1、构造方法:使用UnpooledDataSource方法返回UnpooledDataSource对象,同时生成数据源的hashcode(由url+username+password的hashcode)
    public PooledDataSource(String driver, String url, String username, String password) {
    dataSource = new UnpooledDataSource(driver, url, username, password);
    expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
    }
    2、从连接池中获得链接,getConnection()是个中间方法,实际调用的是popConnection方法,下面介绍popConnection即从链接池中拿Connection。
    @Override
    public Connection getConnection() throws SQLException {
    return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();
    }
     
    private PooledConnection popConnection(String username, String password) throws SQLException {
      boolean countedWait = false;
      PooledConnection conn = null;
      long t = System.currentTimeMillis();
      int localBadConnectionCount = 0;
    //while + synchronized (state) 用于以同步方式拿出connection
      while (conn == null) {
        synchronized (state) {
    //如果PoolState中的空闲连接数不为空,则直接拿出第一个链接
          if (!state.idleConnections.isEmpty()) {
            // Pool has available connection
            conn = state.idleConnections.remove(0);
            if (log.isDebugEnabled()) {
              log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
            }
          } else {
            // Pool does not have available connection
    //如果PoolState中的空闲连接数为空,但是活动的链接数小于PooledDataSource设置的最大链接数,则可以新建链接
            if (state.activeConnections.size() < poolMaximumActiveConnections) {
              // Can create new connection
              conn = new PooledConnection(dataSource.getConnection(), this);
              if (log.isDebugEnabled()) {
                log.debug("Created connection " + conn.getRealHashCode() + ".");
              }
            } else {
              // Cannot create new connection
    //如果PoolState中的空闲连接数为空,并且活动的链接数不小于PooledDataSource设置的最大链接数,则先获得活动链接中最先使用链接(即最老的),判断是否超时时间,如果超时了,则重新从活动连接池中去掉该连接,然后在PoolState设置一些信息,返回该连接
              PooledConnection oldestActiveConnection = state.activeConnections.get(0);
              long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
              if (longestCheckoutTime > poolMaximumCheckoutTime) {
                // Can claim overdue connection
                state.claimedOverdueConnectionCount++;
                state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
                state.accumulatedCheckoutTime += longestCheckoutTime;
                state.activeConnections.remove(oldestActiveConnection);
                if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
                  oldestActiveConnection.getRealConnection().rollback();
                }
                conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
                oldestActiveConnection.invalidate();
                if (log.isDebugEnabled()) {
                  log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
                }
              } else {
                // Must wait
    //如果PoolState中的空闲连接数为空,并且活动的链接数不小于PooledDataSource设置的最大链接数,则先获得活动链接中最先使用链接(即最老的),判断是否超时时间,如果没有超时,则必须等待
                try {
                  if (!countedWait) {
                    state.hadToWaitCount++;
                    countedWait = true;
                  }
                  if (log.isDebugEnabled()) {
                    log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
                  }
                  long wt = System.currentTimeMillis();
                  state.wait(poolTimeToWait);
                  state.accumulatedWaitTime += System.currentTimeMillis() - wt;
                } catch (InterruptedException e) {
                  break;
                }
              }
            }
          }
    //获得conn后,需要进一步判断该连接状态,包括非空校验等
          if (conn != null) {
            if (conn.isValid()) {
              if (!conn.getRealConnection().getAutoCommit()) {
                conn.getRealConnection().rollback();
              }
              conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
              conn.setCheckoutTimestamp(System.currentTimeMillis());
              conn.setLastUsedTimestamp(System.currentTimeMillis());
              state.activeConnections.add(conn);
              state.requestCount++;
              state.accumulatedRequestTime += System.currentTimeMillis() - t;
            } else {
              if (log.isDebugEnabled()) {
                log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection.");
              }
              state.badConnectionCount++;
              localBadConnectionCount++;
              conn = null;
              if (localBadConnectionCount > (poolMaximumIdleConnections + 3)) {
                if (log.isDebugEnabled()) {
                  log.debug("PooledDataSource: Could not get a good connection to the database.");
                }
                throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
              }
            }
          }
        }
    
      }
    
      if (conn == null) {
        if (log.isDebugEnabled()) {
          log.debug("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
        }
        throw new SQLException("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
      }
    
      return conn;
    }
    3、向连接池中push连接。
    protected void pushConnection(PooledConnection conn) throws SQLException {
    
      synchronized (state) {
        state.activeConnections.remove(conn);
        if (conn.isValid()) {
          if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
            state.accumulatedCheckoutTime += conn.getCheckoutTime();
            if (!conn.getRealConnection().getAutoCommit()) {
              conn.getRealConnection().rollback();
            }
    //主要工作是根据传入conn重新生成PooledConnection ,然后把con设置失效
            PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
            state.idleConnections.add(newConn);
            newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
            newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
            conn.invalidate();
            if (log.isDebugEnabled()) {
              log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");
            }
    //通知其他等待连接的PooledDataSource,可以pop连接了
            state.notifyAll();
          } else {
            state.accumulatedCheckoutTime += conn.getCheckoutTime();
            if (!conn.getRealConnection().getAutoCommit()) {
              conn.getRealConnection().rollback();
            }
            conn.getRealConnection().close();
            if (log.isDebugEnabled()) {
              log.debug("Closed connection " + conn.getRealHashCode() + ".");
            }
            conn.invalidate();
          }
        } else {
          if (log.isDebugEnabled()) {
            log.debug("A bad connection (" + conn.getRealHashCode() + ") attempted to return to the pool, discarding connection.");
          }
          state.badConnectionCount++;
        }
      }
    }
    4、设置各种属性时都会调用forceCloseAll()方法,按照注解的意思是关闭所有活动的和空闲的连接。
    /*
     * Closes all active and idle connections in the pool
     */
    public void forceCloseAll() {
      synchronized (state) {
        expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
        for (int i = state.activeConnections.size(); i > 0; i--) {
          try {
            PooledConnection conn = state.activeConnections.remove(i - 1);
            conn.invalidate();
    
            Connection realConn = conn.getRealConnection();
            if (!realConn.getAutoCommit()) {
              realConn.rollback();
            }
            realConn.close();
          } catch (Exception e) {
            // ignore
          }
        }
        for (int i = state.idleConnections.size(); i > 0; i--) {
          try {
            PooledConnection conn = state.idleConnections.remove(i - 1);
            conn.invalidate();
    
            Connection realConn = conn.getRealConnection();
            if (!realConn.getAutoCommit()) {
              realConn.rollback();
            }
            realConn.close();
          } catch (Exception e) {
            // ignore
          }
        }
      }
      if (log.isDebugEnabled()) {
        log.debug("PooledDataSource forcefully closed/removed all connections.");
      }
    }
    5、获得操作数据库的实际连接,即未包装过的连接,通过动态代理方式获得连接对象
    /*
     * Unwraps a pooled connection to get to the 'real' connection
     *
     * @param conn - the pooled connection to unwrap
     * @return The 'real' connection
     */
    public static Connection unwrapConnection(Connection conn) {
      if (Proxy.isProxyClass(conn.getClass())) {
        InvocationHandler handler = Proxy.getInvocationHandler(conn);
        if (handler instanceof PooledConnection) {
          return ((PooledConnection) handler).getRealConnection();
        }
      }
      return conn;
    }
    收藏文章数量从多到少与“把书读薄”是一个道理
  • 相关阅读:
    md基本语法
    CodeBlocks安装使用、汉化以及更改配色
    hexo+github搭建个人博客教程和各种坑记录
    GB/T 38637.1-2020 物联网 感知控制设备接入 第1部分:总体要求
    山东大学909数据结构与程序设计考研经验分享
    GB/T 39083-2020 快递服务支付信息交换规范
    GB/T 38829-2020 IPTV媒体交付系统技术要求 内容接入
    GB/T 37733.3-2020 传感器网络 个人健康状态远程监测 第3部分:终端技术要求
    GB/T 38801-2020 内容分发网络技术要求 互联应用场景
    GB/T 30269.809-2020 信息技术 传感器网络 第809部分:测试:基于IP的无线传感器网络网络层协议一致性测试
  • 原文地址:https://www.cnblogs.com/use-D/p/9570326.html
Copyright © 2011-2022 走看看