zoukankan      html  css  js  c++  java
  • mybatis默认的数据源连接池(PooledDataSource和UnPooledDataSource)

    一般情况下我们操作数据库都是通过connection,但是频繁创建和删除connection会严重影响效率,因此在这种情况下我们一般会用到连接池,因为项目中用到的是mybatis,所以了解一下mybatis的默认的数据库连接池(大多数情况下我们会使用Durid连接池)

    代码路径:

    很明显看到datasource目录下有pooled和unpooled两个目录,分别是使用到了连接池和没有用到

    1、unpooled目录下的UnpooledDatasource.java

    /**
     * @author Clinton Begin
     * @author Eduardo Macarron
     */
    public class UnpooledDataSource implements DataSource {
      
      private ClassLoader driverClassLoader;
      private Properties driverProperties;
      private static Map<String, Driver> registeredDrivers = new ConcurrentHashMap<String, Driver>();
     //常规配置
      private String driver;
      private String url;
      private String username;
      private String password;
     //是否自动commit    事务的隔离级别
      private Boolean autoCommit;
      private Integer defaultTransactionIsolationLevel;
    
     //注册驱动
    static { Enumeration<Driver> drivers = DriverManager.getDrivers(); while (drivers.hasMoreElements()) { Driver driver = drivers.nextElement(); registeredDrivers.put(driver.getClass().getName(), driver); } } public UnpooledDataSource() { } public UnpooledDataSource(String driver, String url, String username, String password) { this.driver = driver; this.url = url; this.username = username; this.password = password; }  //重点getconnnection 获取数据库连接,调用doGetConnection方法 @Override public Connection getConnection() throws SQLException { return doGetConnection(username, password); } @Override public Connection getConnection(String username, String password) throws SQLException { return doGetConnection(username, password); }  //用户名 密码 设置配置 private Connection doGetConnection(String username, String password) throws SQLException { Properties props = new Properties(); if (driverProperties != null) { props.putAll(driverProperties); } if (username != null) { props.setProperty("user", username); } if (password != null) { props.setProperty("password", password); } return doGetConnection(props); }  //真正获取连接的方法,由此可见,每次调用getConnection方法是,都会新建一个Connection对象,可想当并发量高是,数据库的连接就会被占满 private Connection doGetConnection(Properties properties) throws SQLException { initializeDriver(); Connection connection = DriverManager.getConnection(url, properties); configureConnection(connection); return connection; }  //初始化 在调用doGetConnection方法中,会先进行一下判断,判断mybatis的configuration中是否已经有数据库驱动,没有的话会通过反射加载驱动 private synchronized void initializeDriver() throws SQLException { if (!registeredDrivers.containsKey(driver)) { Class<?> driverType; try { if (driverClassLoader != null) { driverType = Class.forName(driver, true, driverClassLoader); } else { driverType = Resources.classForName(driver); } // DriverManager requires the driver to be loaded via the system ClassLoader. // http://www.kfu.com/~nsayer/Java/dyn-jdbc.html Driver driverInstance = (Driver)driverType.newInstance(); DriverManager.registerDriver(new DriverProxy(driverInstance)); registeredDrivers.put(driver, driverInstance); } catch (Exception e) { throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e); } } }  //设置是否自动提交 事务的隔离级别 private void configureConnection(Connection conn) throws SQLException { if (autoCommit != null && autoCommit != conn.getAutoCommit()) { conn.setAutoCommit(autoCommit); } if (defaultTransactionIsolationLevel != null) { conn.setTransactionIsolation(defaultTransactionIsolationLevel); } } }

    2、PolledDataSource.java类,其内部的datasource其实也是通过unpolledDataSource对象来实现的,只是在获取连接connection的时候进行了处理(重点关注getConnection方法)

    public class PooledDataSource implements DataSource {
    
      private static final Log log = LogFactory.getLog(PooledDataSource.class);
     //PollState 充当锁对象,这个对象中也有例如  空闲连接集合,活跃链接集合,请求的数量,等一些变量
      private final PoolState state = new PoolState(this);
     //PolledDataSource中的数据源也是使用的UnpolledDataSource对象来实现的
      private final UnpooledDataSource dataSource;
    
      // OPTIONAL CONFIGURATION FIELDS 线程池的最大活跃数量,最大空闲数量,等待时间等等。。。
      protected int poolMaximumActiveConnections = 10;
      protected int poolMaximumIdleConnections = 5;
      protected int poolMaximumCheckoutTime = 20000;
      protected int poolTimeToWait = 20000;
      protected int poolMaximumLocalBadConnectionTolerance = 3;
      protected String poolPingQuery = "NO PING QUERY SET";
      protected boolean poolPingEnabled;
      protected int poolPingConnectionsNotUsedFor;
     //url+username+password连接起来的字符串的hashcode值
      private int expectedConnectionTypeCode;
    
      public PooledDataSource() {
        dataSource = new UnpooledDataSource();
      }
    
      public PooledDataSource(UnpooledDataSource dataSource) {
        this.dataSource = dataSource;
      }
    
      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());
      }
    
     //获取连接connection @Override
    public Connection getConnection() throws SQLException { return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection(); } @Override public Connection getConnection(String username, String password) throws SQLException { return popConnection(username, password).getProxyConnection(); }  //线程安全的获取连接的方法(供PooledConnection中调用) synchronized protected void pushConnection(PooledConnection conn) throws SQLException {   //所对象为PoolState 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(); } 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."); } 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++; } } } private PooledConnection popConnection(String username, String password) throws SQLException { boolean countedWait = false; PooledConnection conn = null; long t = System.currentTimeMillis(); int localBadConnectionCount = 0; while (conn == null) { synchronized (state) {
         //如果state中空闲的连接不为空时,直接从state中的idelConnections集合中获取
    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 {
          //state中的idelConnections集合中没有连接connection了,判断活跃的connection是否小于最大活跃线程数,小于的话就新建一个connection
    // Pool does not have available connection 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 {
           //当前活跃的connection数大于最大活跃connection数是,表明不能新建connection,这种情况下,会判断是否已经超过设定的时间20s,如果超过,会根据是否自动commit,
           /不是自动提交,会进行rollback操作
    // Cannot create new connection 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()) {//判断是否设置了自动提交,不是自动提交的话,会进行rollback try { oldestActiveConnection.getRealConnection().rollback(); } catch (SQLException e) { /* Just log a message for debug and continue to execute the following statement like nothing happend. Wrap the bad connection with a new PooledConnection, this will help to not intterupt current executing thread and give current thread a chance to join the next competion for another valid/good database connection. At the end of this loop, bad {@link @conn} will be set as null. */ log.debug("Bad connection. Could not roll back"); } }
            //将之前rollback的connection进行处理,重新生成一个connection,并设置创建时间和最后使用时间 conn
    = new PooledConnection(oldestActiveConnection.getRealConnection(), this); conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp()); conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp()); oldestActiveConnection.invalidate(); if (log.isDebugEnabled()) { log.debug("Claimed overdue connection " + conn.getRealHashCode() + "."); } } else {
             //当活跃connection的集合中第一个connection不符合超时,则进行等待wait
    // Must wait try { if (!countedWait) { state.hadToWaitCount++; countedWait = true; }
               //pooltimeTowait默认也是20秒
    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仍然没有值,则会循环走一行流程,第二次一定会获取到conn对象(默认的超时时间是20秒,第一次已经等待过20s了)
    if (conn != null) {
          //判断conn是否能用 通过ping能否ping通
    // ping to server and check the connection is valid or not 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 + poolMaximumLocalBadConnectionTolerance)) { 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、看下创建PooledConnection对象(从上边截出的一部分代码,新建PooledConnection对象)

     // Pool does not have available connection
              if (state.activeConnections.size() < poolMaximumActiveConnections) {
                // Can create new connection
                conn = new PooledConnection(dataSource.getConnection(), this);
                if (log.isDebugEnabled()) {
                  log.debug("Created connection " + conn.getRealHashCode() + ".");
                }
              }

    PooledConnection构造函数:PooledConnection函数实现了InvocationHandler接口(动态代理)

      public PooledConnection(Connection connection, PooledDataSource dataSource) {
        this.hashCode = connection.hashCode();
        this.realConnection = connection;
        this.dataSource = dataSource;
        this.createdTimestamp = System.currentTimeMillis();
        this.lastUsedTimestamp = System.currentTimeMillis();
        this.valid = true;
        this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);
      }
    
     @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
      //判断是否close,如果是close的话,会调用PooledDataSource中的pushConnection方法,将该conn从activeConnections删除,同时将此conn添加到idelConnections中
    if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) { dataSource.pushConnection(this); return null; } else { try { if (!Object.class.equals(method.getDeclaringClass())) { // issue #579 toString() should never fail // throw an SQLException instead of a Runtime checkConnection(); } return method.invoke(realConnection, args); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } }

    参考:https://blog.csdn.net/drxRose/article/details/85710850

    https://www.jianshu.com/p/21cf094cb97b?open_source=weibo_search

  • 相关阅读:
    HTML5 GeoLocation 地理定位
    HTML5 LocalStorage 本地存储
    JS-事件代理(委托)
    面向对象(封装、继承、多态)
    js图片预加载
    jQuery 事件
    svn无法验证
    Ext.data.Store(转)
    ExtJS实现Excel导出(转)
    <![CDATA[ ]]> 意思
  • 原文地址:https://www.cnblogs.com/nxzblogs/p/11103230.html
Copyright © 2011-2022 走看看