连接池技术:
- 连接池是什么:存储连接的容器
作用
如果没有连接池,那么每次都执行SQL语句都会创建connection连接,会浪费时间。影响程序的性能。提前创建一些连接,存储到连接池中,使用的时候从连接池中获取连接即可。
常用的连接池
- C3P0连接池
- DBCP连接池
- Druid连接池(阿里)
连接池最后要归还
MyBatis连接池的分类
MyBatis内置了连接池技术,dataSource标签的type属性有2个取值:
mybatis支持三种内置的数据源类型:
POOLED:实现dataSource接口,使用连接池。
UNPOOLED:同样也是实现了dataSource接口,不使用池。
JDNI:采用服务器提供的JDNI技术实现的,并且在不同服务器之间获取的连接池是不一样的。(限制maven或者web的war工程)
MyBatis连接池的实现原理分析
- 在解析SqlMapConfig配置文件的时候,创建dataSource对象,存入到Environment对象中。
- 当执行SQL语句的时候,准备从dataSource对象中获取链接。
- PooledDataSource源码中的2个方法用来获取连接和归还连接
popConnection方法用来获取链接
–synchronized(this.state){}保证线程安全
- 先判断空闲连接池中是否存在连接,如果存在,则获取一个连接使用;如果没有连接则去活动连接池创建
- 查看activeConnections活动连接池是否已满;如果没有满,则创建一个新的PooledConnection对象,然后放到activeConnections池中,然后返回此PooledConnection对象。
- 如果满了 看最先进入activeConnections池中的PooledConnection对象是否已经过期:如果已经过期,从activeConnections池中移除此对象,然后创建一个新的PooledConnection对象,添加到activeConnections中,然后将此对象返回。
pushConnection方法用来归还连接
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(this.state) {
PoolState var10000;
//判断存在连接
if (!this.state.idleConnections.isEmpty()) {
conn = (PooledConnection)this.state.idleConnections.remove(0);
if (log.isDebugEnabled()) {
log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
}
} //查看活动连接池是否满了
else if (this.state.activeConnections.size() < this.poolMaximumActiveConnections) {
conn = new PooledConnection(this.dataSource.getConnection(), this);
if (log.isDebugEnabled()) {
log.debug("Created connection " + conn.getRealHashCode() + ".");
}
} else {
//拿出最老的连接,放入新连接
PooledConnection oldestActiveConnection = (PooledConnection)this.state.activeConnections.get(0);
long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
if (longestCheckoutTime > (long)this.poolMaximumCheckoutTime) {
++this.state.claimedOverdueConnectionCount;
var10000 = this.state;
var10000.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
var10000 = this.state;
var10000.accumulatedCheckoutTime += longestCheckoutTime;
this.state.activeConnections.remove(oldestActiveConnection);
if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
try {
oldestActiveConnection.getRealConnection().rollback();
} catch (SQLException var15) {
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) {
++this.state.hadToWaitCount;
countedWait = true;
}
if (log.isDebugEnabled()) {
log.debug("Waiting as long as " + this.poolTimeToWait + " milliseconds for connection.");
}
long wt = System.currentTimeMillis();
this.state.wait((long)this.poolTimeToWait);
var10000 = this.state;
var10000.accumulatedWaitTime += System.currentTimeMillis() - wt;
} catch (InterruptedException var16) {
break;
}
}
}
if (conn != null) {
if (conn.isValid()) {
if (!conn.getRealConnection().getAutoCommit()) {
conn.getRealConnection().rollback();
}
conn.setConnectionTypeCode(this.assembleConnectionTypeCode(this.dataSource.getUrl(), username, password));
conn.setCheckoutTimestamp(System.currentTimeMillis());
conn.setLastUsedTimestamp(System.currentTimeMillis());
this.state.activeConnections.add(conn);
++this.state.requestCount;
var10000 = this.state;
var10000.accumulatedRequestTime += System.currentTimeMillis() - t;
} else {
if (log.isDebugEnabled()) {
log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection.");
}
++this.state.badConnectionCount;
++localBadConnectionCount;
conn = null;
if (localBadConnectionCount > this.poolMaximumIdleConnections + this.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.");
} else {
return conn;
}
}