下面是数据源模块主要源码, 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 的相关内容到这里就全部介绍完了 。