DBCP2获取连接
如果是初次获取连接会进行一系列操作,如下图所示;
包括:
- 在静态初始化BasicDataSource时加载相关类,避免在使用getConnection获取连接时有些类没被加载导致AccessControlException
- createConnectonFactory创建Connection工厂,用于获取原生物理连接。这边有个有趣的操作是在当前类加载器获取不到驱动类时,尝试使用当前线程上线文类加载器去获取
- createPoolableConnectionFactory,创建池化连接池,用于封装和管理原生Connection,包括:
- activateObject,设置连接是否默认提交、事务隔离级别、是否只读、语句查询超时时间,这些都可以配置
- validateConnection,验证连接是否可用,有两个方式:1.没有配置validationQuery属性时,采用数据库驱动提供的验证方式;2.有配置的话,通过配置发送查询语句。暂时不清楚两种方式优劣,感觉直接采用官方提供的比较靠谱
- passivateObject,用于归还或销毁连接时,如果设置rollbackOnReturn为true(默认为true),且在activateObject中设置连接为不自动提交和不是只读,则在归还连接时进行回滚。如果设置enableAutoCommitOnReturn为true(默认为true)如果连接不是自动提交,则设置为自动提交,用于确保空闲连接可自动提交。
上面三个方法都会先验证池化Connection的生命时长(配置参数maxConnLifetimeMillis控制),如果超过则抛出异常
- createConnectionPool,创建连接池,采用生产者消费者模式管理池化连接,处理并发问题
获取连接的调用顺序BasicDataSource.getConnection -> PoolingDataSource.getConnection -> GenericObjectPool.borrowObject ->PoolableConnectionFactory.makeFacotory
下面直接上代码:
在GenericObjectPool类
public T borrowObject(long borrowMaxWaitMillis) throws Exception {
assertOpen();
AbandonedConfig ac = this.abandonedConfig;
if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
(getNumIdle() < 2) &&
(getNumActive() > getMaxTotal() - 3) ) {
removeAbandoned(ac);
}
PooledObject<T> p = null;
// Get local copy of current config so it is consistent for entire
// method execution
boolean blockWhenExhausted = getBlockWhenExhausted();
boolean create;
long waitTime = System.currentTimeMillis();
while (p == null) {
create = false;
if (blockWhenExhausted) {
p = idleObjects.pollFirst();
if (p == null) {
p = create();
if (p != null) {
create = true;
}
}
if (p == null) {
if (borrowMaxWaitMillis < 0) {
p = idleObjects.takeFirst();
} else {
p = idleObjects.pollFirst(borrowMaxWaitMillis,
TimeUnit.MILLISECONDS);
}
}
if (p == null) {
throw new NoSuchElementException(
"Timeout waiting for idle object");
}
if (!p.allocate()) {
p = null;
}
} else {
p = idleObjects.pollFirst();
if (p == null) {
p = create();
if (p != null) {
create = true;
}
}
if (p == null) {
throw new NoSuchElementException("Pool exhausted");
}
if (!p.allocate()) {
p = null;
}
}
if (p != null) {
try {
factory.activateObject(p);
} catch (Exception e) {
try {
destroy(p);
} catch (Exception e1) {
// Ignore - activation failure is more important
}
p = null;
if (create) {
NoSuchElementException nsee = new NoSuchElementException(
"Unable to activate object");
nsee.initCause(e);
throw nsee;
}
}
if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
boolean validate = false;
Throwable validationThrowable = null;
try {
validate = factory.validateObject(p);
} catch (Throwable t) {
PoolUtils.checkRethrow(t);
validationThrowable = t;
}
if (!validate) {
try {
destroy(p);
destroyedByBorrowValidationCount.incrementAndGet();
} catch (Exception e) {
// Ignore - validation failure is more important
}
p = null;
if (create) {
NoSuchElementException nsee = new NoSuchElementException(
"Unable to validate object");
nsee.initCause(validationThrowable);
throw nsee;
}
}
}
}
}
updateStatsBorrow(p, System.currentTimeMillis() - waitTime);
return p.getObject();
}
获取连接分两种情况:
1. 设置超时等待的情况,先尝试从空闲队列获取连接(不等待直接返回),不成功采用超时等待方式从空闲队列获取连接,如果没有获取连接则抛出异常。如果获取成功则激活连接、根据配置(testOnBorrow或testOnCreate)验证连接
2. 没设置超时等待情况,尝试从空闲队列获取连接(不等待直接返回)
注意,在获取连接时,如果符合下面条件将会回收弃用连接:
if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
(getNumIdle() < 2) &&
(getNumActive() > getMaxTotal() - 3) ) {
removeAbandoned(ac);
}