Mybatis源码学习第二课---基础支持层数据源模块分析

下面是数据源模块主要源码, unpooled 代码是不带数据两次池的,pooled是mybatis提供简单的数据连接池。

          

一、DataSourceFactory

      在数据源模块中, DataSourceFactory 接口扮演工厂接口的角色。 UnpooledDataSourceFactory 和 PooledDataSourceFactory 则扮演着具体工厂类的角色。我们从 DataSourceFactory 接口开始分 析,其定义如下:

public interface DataSourceFactory {

  //设置datasource相关属性
  void setProperties(Properties props);
   //获取datasource
  DataSource getDataSource();
}

      在 UnpooledDataSourceFactory 的构造函数中会直接创建 UnpooledDataSource 对象,并初始化 UnpooledDataSourceFactory.dataSource 宇段。 UnpooledDataSourceFactory.setProperties()方法会完成对 UnpooledDataSource 对象的配置,代码如下:

//不用连接池的数据连接工厂
public class UnpooledDataSourceFactory implements DataSourceFactory {

  private static final String DRIVER_PROPERTY_PREFIX = "driver.";
  private static final int DRIVER_PROPERTY_PREFIX_LENGTH = DRIVER_PROPERTY_PREFIX.length();

  protected DataSource dataSource;

  public UnpooledDataSourceFactory() {
    this.dataSource = new UnpooledDataSource();
  }

  @Override
  public void setProperties(Properties properties) {
    Properties driverProperties = new Properties();
    //创建 DataSource 相应的 MetaObject
    MetaObject metaDataSource = SystemMetaObject.forObject(dataSource);
    //遍历 properties 集合,该集合中自己置了数据源需要的信息
    for (Object key : properties.keySet()) {
      String propertyName = (String) key;
      if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) {
        String value = properties.getProperty(propertyName);
        //以”driver . ”开头的自己置项是对 DataSource 的配置,记录到 driverProperties 中保存
        driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value);
      } else if (metaDataSource.hasSetter(propertyName)) {//是否有该属性的 setter 方法
        String value = (String) properties.get(propertyName);
        //根据属性类型进行类型转换, 主要是 Integer、 Long、 Boolean 三种类型的转换
        Object convertedValue = convertValue(metaDataSource, propertyName, value);
        //设置 DataSource 的相关属性值
        metaDataSource.setValue(propertyName, convertedValue);
      } else {
        throw new DataSourceException("Unknown DataSource property: " + propertyName);
      }
    }
    if (driverProperties.size() > 0) {
      metaDataSource.setValue("driverProperties", driverProperties);
    }
  }

  @Override
  public DataSource getDataSource() {
    return dataSource;
  }

   ..........

}

     PooledDataSourceFactory 继承了 UnpooledDataSourceFactory,但并没有覆盖 setProperties() 方法和 getDataSource()方法。两者唯一的区别是 PooledDataSourceFactory 的构造函数会将其 dataSource 字段初始化为 PooledDataSource 对象。

public class PooledDataSourceFactory extends UnpooledDataSourceFactory {

  public PooledDataSourceFactory() {
    this.dataSource = new PooledDataSource();
  }

}

JndiDataSourceFactory 是依赖开IDI 服务从容器中获取用户配置的 DataSource,其逻辑并不 复杂,这里就不再赘述了 。

二、UnpooledDataSource

        javax叫l.DataSource 接口在数据源模块中扮演了产品接口 的角色, MyBatis 提供了两个 DataSource 接口的实现类,分别是 UnpooledDataSource 和 PooledDataSource,它们扮演着具体 产品类的角色。 UnpooledDataSource实现了DataSource接口中定义的getConnection()方法及其重载方法,用于获取数据库连接。每次通过 UnpooledDataSource. getConnection()方法获取数据库连接 时都会创建一个新连接。 UnpooledDataSource 中的宇段如下,每个字段都有对应的 getter/setter 方法:

 //驱动类加载器
  private ClassLoader driverClassLoader;
  //数据库连接相关配置信息
  private Properties driverProperties;
  //缓存已经注册过的驱动类
  private static Map<String, Driver> registeredDrivers = new ConcurrentHashMap<>();

  private String driver;
  private String url;
  private String username;
  private String password;

  private Boolean autoCommit;//是否自动提交
  private Integer defaultTransactionIsolationLevel;//事务隔离级别
  private Integer defaultNetworkTimeout;

     熟悉 JDBC 的读者知道,创建数据库连接之前, 需要先向 DriverManager注册 JDBC 驱动类。 我们以 MySQL 提供的 JDBC 驱动为例进行简单分析, com.mysql抖be.Driver 中有如下静态代码 块:

  static {
    // 向 OriverManager 注册 JOBC 驱动
    Enumeration<Driver> drivers = DriverManager.getDrivers();
    while (drivers.hasMoreElements()) {
      Driver driver = drivers.nextElement();
      registeredDrivers.put(driver.getClass().getName(), driver);
    }
  }

     UnpooledDataSource.getConnection()方法的所有重载最终会调用 UnpooledDataSource.doGetConnection()方法获取数据库连接,具体实现如下:

//从这个代码可以看出,unpooledDatasource获取连接的方式和手动获取连接的方式是一样的
  private Connection doGetConnection(Properties properties) throws SQLException {
    //初始化数据库驱动
    initializeDriver();
    //创建真正的数据库连接
    Connection connection = DriverManager.getConnection(url, properties);
    //配置数据库连接的 autoCommit 和隔离级别
    configureConnection(connection);
    return connection;
  }

       UnpooledDataSource.initializeDriver()方法主要负责数据库驱动的初始化,该方法会创建配 置中指定的 Driver 对象,并将其注册到 DriverManager 以及上面介绍的 UnpooledDataSource.registeredDrivers 集合中保存。

 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);
        }
        //创建Driver类
        Driver driverInstance = (Driver)driverType.getDeclaredConstructor().newInstance();
        //注册驱动, DriverProxy 是定义在 UnpooledDataSource 中的内部类,是 Driver 的静态代理类
        DriverManager.registerDriver(new DriverProxy(driverInstance));
        //放入缓存中
        registeredDrivers.put(driver, driverInstance);
      } catch (Exception e) {
        throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
      }
    }
  }

    UnpooledDataSource.configureConnection()方法主要完成数据库连接的一系列配置, 具体实 现如下:

 private void configureConnection(Connection conn) throws SQLException {
    if (defaultNetworkTimeout != null) {
      conn.setNetworkTimeout(Executors.newSingleThreadExecutor(), defaultNetworkTimeout);
    }
    if (autoCommit != null && autoCommit != conn.getAutoCommit()) {
      conn.setAutoCommit(autoCommit);
    }
    if (defaultTransactionIsolationLevel != null) {
      conn.setTransactionIsolation(defaultTransactionIsolationLevel);
    }
  }

三、PooledDataSource

       了解 JDBC 编程的读者知道,数据库连接的创建过程是非常耗时的,数据库能够建立的连 接数也非常有限,所以在绝大多数系统中,数据库连接是非常珍贵的资源,使用数据库连接池就显得尤为必要。使用数据库连接池会带来很多好处,例如,可以实现数据库连接的重用、提 高响应速度、防止数据库连接过多造成数据库假死、避免数据库连接泄露等。 

     数据库连接池在初始化的时候,一般会创建一定数量的数据连接并添加到连接池中备用。当程序需要使用数据库连接时,从池中请求连接,当程序不需要使用数据库连接时,不是关闭数据库连接而是放到池子中。当然,数据库连接池会控制连接总数的上限以及空闲 连接数的上限,如果连接池创建的总连接数己达到上限,且都己被占用,则后续请求连接的线程会进入阻塞队列等待,直到有钱程释放出可用的连接。 如果连接池中空闲连接数较多,达到 其上限, 则后续返回的空闲连接不会放入池中,而是直接关闭,这样可以减少系统维护多余数 据库连接的开销。 

           如果将总连接数的上限设置得过大,可能因连接数过多而导致数据库僵死,系统整体性能 下降;如果总连接数上限过小,则无法完全发挥数据库的性能,浪费数据库资源。如果将空闲 连接的上限设置得过大,则会浪费系统资源来维护这些空闲连接:如果空闲连接上限过小,当 出现瞬间的峰值请求时,系统的快速响应能力就比较弱。所以在设置数据库连接池的这两个值 时,需要进行性能测试、权衡以及一些经验。

            PooledDataSource 实现了简易数据库连接池的功能,它依赖的组件下图 所示,其中需 要注意的是, PooledDataSource 创建新数据库连接的功能是依赖其中封装的 UnpooledDataSource 对象实现的。

                    

   1、PooledConnection:使用动态代理封装了真正的数据库连接对象;
   2、PoolState:用于管理PooledConnection对象状态的组件,通过两个list分别 管理空闲状态的连接资源和活跃状态的连
接资源
   3、PooledDataSource:一个简单,同步的、线程安全的数据库连接池

   PooledDataSource 并不会直接管理java. sqI.Connection 对象,而是管理 PooledConnection 对 象。在 PooledConnection 中封装了真正的数据库连接对象(java.sql.Connection)以及其代理对 象,这里的代理对象是通过 JDK 动态代理产生的。 PooledConnection 继承了 lnvocationHandler 接口,该接口在前面介绍 JDK 动态代理时已经详细描述过了,这里不再重复。

PooledConnection 中的核心字段如下:

/**
 * 使用动态代理封装了真正的数据库连接对象
 * @author Clinton Begin
 */
class PooledConnection implements InvocationHandler {

  private static final String CLOSE = "close";
  private static final Class<?>[] IFACES = new Class<?>[] { Connection.class };

  private final int hashCode;
  //记录当前连接所在的数据源对象,本次连接是有这个数据源创建的,关闭后也是回到这个数据源;
  private final PooledDataSource dataSource;
  //真正的数据连接
  private final Connection realConnection;
  //数据库连接的代理对象
  private final Connection proxyConnection;
  //从数据源取出来连接的时间戳
  private long checkoutTimestamp;
  //数据库连接创建的时间
  private long createdTimestamp;
  //数据库连接最后一次使用的时间
  private long lastUsedTimestamp;
  //根据数据库url、用户名、密码生成一个hash值,唯一标识一个连接池
  private int connectionTypeCode;
  //检测当前 PooledConnection 是否有效,主要是为了防止程序通过 close()
  // 方法将连接归还给连接池之后,依然通过该连接操作数据库
  private boolean valid;

        PooledConnection 中提供了上述字段的 getter/setter 方法,代码比较简单。这里重点关注 PooledConnection.invoke()方法的实现,该方法是 proxyConn巳ction 这个连接代理对象的真正代理 逻辑,它会对 close()方法的调用进行代理,并且在调用真正数据库连接的方法之前进行检测, 代码如下:

  /**
   * Required for InvocationHandler implementation.
   *此方法专门用来增强数据库connect对象,使用前检查连接是否有效,关闭时对连接进行回收
   * @param proxy  - not used
   * @param method - the method to be executed
   * @param args   - the parameters to be passed to the method
   * @see java.lang.reflect.InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])
   */
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    //如果是数据库连接关闭的方法,不用关闭连接而是放到连接池中
    if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {
      //把数据库连接归还到池中
      dataSource.pushConnection(this);
      return null;
    }
    try {
      //如果不是Object方法 检查数据连接是否可以用
      if (!Object.class.equals(method.getDeclaringClass())) {
        checkConnection();
      }
      //返回真正的操作
      return method.invoke(realConnection, args);
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

     PoolState 是用于管理 PooledConnection 对象状态的组件,它通过两个 ArrayList <Pooled Connection>集合分别管理空闲状态的连接和活跃状态的连接,PoolState 中还定义了一系列用于统计的字段,定义如下:

 //此次数据库连接的数据源
  protected PooledDataSource dataSource;

  //空闲的连接池资源集合
  protected final List<PooledConnection> idleConnections = new ArrayList<>();
  //活跃的连接池资源集合
  protected final List<PooledConnection> activeConnections = new ArrayList<>();
  //请求次数
  protected long requestCount = 0;
  //累计的获得连接的时间
  protected long accumulatedRequestTime = 0;
  //累计的使用连接的时间。从连接取出到归还,算一次使用的时间;
  protected long accumulatedCheckoutTime = 0;
  //累计使用次数
  protected long claimedOverdueConnectionCount = 0;
  //累计超时时间
  protected long accumulatedCheckoutTimeOfOverdueConnections = 0;
  //累计等待时间
  protected long accumulatedWaitTime = 0;
  //等待次数
  protected long hadToWaitCount = 0;
  //无效的连接次数
  protected long badConnectionCount = 0;

   PooledDataSource 中管理的真正的数据库连接对象是由 PooledDataSource 中封装的UnpooledDataSource 对象创建的,并由 PoolState 管理所有连接的状态。 PooledDataSource 中核 心字段的含义和功能如下:
      

 //通过 PoolState 管理连接池的状态并记录统计信息
  private final PoolState state = new PoolState(this);

  //使用UnpooledDataSource数据源 创建数据库连接
  private final UnpooledDataSource dataSource;

  // OPTIONAL CONFIGURATION FIELDS
  //数据连接池中最大活跃连接数
  protected int poolMaximumActiveConnections = 10;
  //数据库连接池 最大空闲连接数
  protected int poolMaximumIdleConnections = 5;
  //最大checkout时长(最长使用时间)
  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、用户名、密码生成一个hash值,唯一标识一个连接池,由这个连接池生成的连接都会带上这个值
  private int expectedConnectionTypeCode;

     PooledDataSource.getConnection()方法首先会调用 PooledDataSource.popConnection()方法获 取 PooledConnection 对象,然后通过 PooledConnection.getProxyConnection()方法获取数据库连 接的代理对象。 popConnection()方法是 PooledDataSource 的核心逻辑之一,其具体逻辑如下图:

                     

 

PooledDataSource. popConnection()方法的具体实现如下:
    

  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) {
        //判断池中是否有空闲连接数 如果有直接从池子中取连接
        if (!state.idleConnections.isEmpty()) {
          //有空闲连接直接使用
          conn = state.idleConnections.remove(0);
          if (log.isDebugEnabled()) {
            log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
          }
        } else {// 没有空闲连接
          if (state.activeConnections.size() < poolMaximumActiveConnections) {//判断活跃连接池中的数量是否大于最大连接数
            // 没有则可创建新的连接
            conn = new PooledConnection(dataSource.getConnection(), this);
            if (log.isDebugEnabled()) {
              log.debug("Created connection " + conn.getRealHashCode() + ".");
            }
          } else {// 如果已经等于最大连接数,则不能创建新连接
            // 获取最先创建的活跃连接,判断其是否超时
            PooledConnection oldestActiveConnection = state.activeConnections.get(0);
            long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
            //检测是否已经以及超过最长使用时间
            if (longestCheckoutTime > poolMaximumCheckoutTime) {
              // 如果超时,对超时连接的信息进行统计
              state.claimedOverdueConnectionCount++;//超时连接次数+1
              state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;//累计超时时间增加
              state.accumulatedCheckoutTime += longestCheckoutTime;//累计的使用连接的时间增加
              state.activeConnections.remove(oldestActiveConnection);//从活跃队列中删除
              //如果超时连接未提交,则手动回滚
              if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
                try {
                  oldestActiveConnection.getRealConnection().rollback();
                } catch (SQLException e) {
                  log.debug("Bad connection. Could not roll back");
                }
              }
              //在连接池中创建新的连接,注意对于数据库来说,并没有创建新连接;
              //只是根据原先的数据库连接生产新的代理连接
              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 {
              // 无空闲连接,最早创建的连接没有失效,无法创建新连接,只能阻塞
              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;
              }
            }
          }
        }
        //获取连接成功的,要测试连接是否有效,同时更新统计数据
        if (conn != null) {
          // 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;
  }

通过前面对 PooledConnection.invoke()方法的分析我们知道, 当调用连接的代理对象的 close()方法时,并未关闭真正的数据连接,而是调用 PooledDataSource.pushConnection()方法将 PooledConnection 对象归还给连接池,供之后重用 。 PooledDataSource.pushConnection()方法也是 PooledDataSource 的核心逻辑之一,其逻辑如下图所示。
         

方法的具体实现如下:

  /**
   * 归还连接
   * @param conn
   * @throws SQLException
   */
  protected void pushConnection(PooledConnection conn) throws SQLException {

    synchronized (state) {//同步、
      //移除池子这个获取的连接
      state.activeConnections.remove(conn);
      //判断此连接是否有效
      if (conn.isValid()) {
        //判断闲置连接池资源是否已经达到上限以及 PooledConnection 是否为该连接池的连接
        if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
          state.accumulatedCheckoutTime += conn.getCheckoutTime();
          //如果有未提交的事务 则回滚
          if (!conn.getRealConnection().getAutoCommit()) {
            conn.getRealConnection().rollback();
          }
          //为返还连接创建新的 PooledConnection 对象
          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++;
      }
    }
  }

       这里需要注意的是, PooledDataSource.pushConnection()方法和 popConnection()方法中都调 用了 PooledConnection.isValid()方法来检测 PooledConnection 的有效性 , 该方法除了检测 PooledConnection. valid 宇段的值,还会调用 PooledDataSource.pingConnection()方法尝试让数据 库执行 poolPingQuery 字段中记录的测试 SQL 语句,从而检测真正的数据库连接对象是否依然 可以正常使用。 isValid()方法以及 pingConnection()方法的代码如下:
 

 public boolean isValid() {
    return valid && realConnection != null && dataSource.pingConnection(this);
  }
  protected boolean pingConnection(PooledConnection conn) {
    boolean result = true;//记录 ping 操作是否成功
    try {
      //检测真正的数据库连接是否已经关闭
      result = !conn.getRealConnection().isClosed();
    } catch (SQLException e) {
      if (log.isDebugEnabled()) {
        log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage());
      }
      result = false;
    }
   //没有被关闭
    if (result) {
      if (poolPingEnabled) {//检测 poolPingEnabled 设置,是否运行执行测试 SQL 语句
        //长时间(超过 poolPingConnectionsNotUsedFor 指定的时长)未使用的连接,才需要 ping
        //操作来检测数据库连接是否正常
        if (poolPingConnectionsNotUsedFor >= 0 && conn.getTimeElapsedSinceLastUse() > poolPingConnectionsNotUsedFor) {
          try {
            if (log.isDebugEnabled()) {
              log.debug("Testing connection " + conn.getRealHashCode() + " ...");
            }
            //下面是执行测试 SQL 语句的 JDBC 操作,不多做解释
            Connection realConn = conn.getRealConnection();
            try (Statement statement = realConn.createStatement()) {
              statement.executeQuery(poolPingQuery).close();
            }
            if (!realConn.getAutoCommit()) {
              realConn.rollback();
            }
            result = true;
            if (log.isDebugEnabled()) {
              log.debug("Connection " + conn.getRealHashCode() + " is GOOD!");
            }
          } catch (Exception e) {
            log.warn("Execution of ping query '" + poolPingQuery + "' failed: " + e.getMessage());
            try {
              conn.getRealConnection().close();
            } catch (Exception e2) {
              //ignore
            }
            result = false;
            if (log.isDebugEnabled()) {
              log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage());
            }
          }
        }
      }
    }
    return result;
  }

     最后需要注意的是 PooledDataSource.forceCloseAIl()方法,当修改 PooledDataSource 的字段 时,例如数据库 URL、用户名、 密码、 autoCornmit 配置等, 都会调用 forceCloseAII()方法将所 有数据库连接关 闭, 同 时也会将所有相应 的 PooledConnection 对象都设置为无效,清空 前tiveConnecti ons 集合 和 idleConnections 集合。应用系统之后通过 PooledDataSource.getConnection() 获 取连 接 时 ,会 按照新的配置重新创建新的数据库连接以 及 相 应 的 PooledConnection 对象。 forceCloseAll()方法的具体实现如下:
     

 public void forceCloseAll() {
    synchronized (state) {
      //更新当前连接池的标识
      expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
      //处理全部的活跃连接
      for (int i = state.activeConnections.size(); i > 0; i--) {
        try {
          //从 PoolState.activeConnections 集合中获取 PooledConnection 对象
          PooledConnection conn = state.activeConnections.remove(i - 1);
          //将 PooledConnection 对象设置为元效
          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.");
    }
  }

DataSource 的相关内容到这里就全部介绍完了 。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值