詳解Mybatis中的PooledDataSource
前言
上篇Java Mybatis數(shù)據(jù)源之工廠模式文章中我們介紹了Mybatis的數(shù)據(jù)源模塊的DataSource接口和它對(duì)應(yīng)的實(shí)現(xiàn)類UnpooledDataSource、PooledDataSource,這篇文章詳細(xì)介紹一下PooledDataSource
PooledDataSource使用了數(shù)據(jù)庫(kù)連接池可以實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接池的重復(fù)利用,還能控制連接數(shù)據(jù)庫(kù)的連接上限,實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接的統(tǒng)一管理,緩存數(shù)據(jù)連接信息還能防止流量突發(fā)連接數(shù)據(jù)庫(kù)不及時(shí)
PooledDataSource有個(gè)PoolState狀態(tài),PoolState里保存著數(shù)據(jù)庫(kù)連接信息PooledConnection,PooledConnection實(shí)現(xiàn)InvocationHandler接口,重寫invoke方法,顯然這是一個(gè)代理類,使用了JDK的動(dòng)態(tài)代理
PooledConnection
class PooledConnection implements InvocationHandler {
private static final Class<?>[] IFACES = new Class<?>[] { Connection.class };
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();
if (CLOSE.equals(methodName)) {
dataSource.pushConnection(this);
return null;
}
try {
if (!Object.class.equals(method.getDeclaringClass())) {
checkConnection();
}
return method.invoke(realConnection, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
}我們看一看到構(gòu)造方法中調(diào)用了Proxy.newProxyInstance()方法來(lái)生成代理類,而重寫invoke方法中如果是close()就調(diào)用pushConnection()方法直接把它放入連接池而不是關(guān)閉連接,其他情況調(diào)用checkConnection()檢查連接信息,代理類調(diào)用realConnection()方法,下面就看一下pushConnection()方法
PooledDataSource的pushConnection()方法
方法的功能就是把數(shù)據(jù)庫(kù)連接放入連接池中:
protected void pushConnection(PooledConnection conn) throws SQLException {
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++;
}
}
}- 從活躍連接集合中刪除該連接
- 如果PooledConnection有效,并且空閑連接數(shù)小于最大空閑連接數(shù),就利用當(dāng)前PooledConnection創(chuàng)建PooledConnection,放入空閑連接數(shù)集合中,方便下次使用,關(guān)閉當(dāng)前PooledConnection對(duì)象的數(shù)據(jù)庫(kù)連接,并對(duì)當(dāng)前PooledConnection對(duì)象設(shè)置無(wú)效,最后喚醒其他等待的線程。如果空閑連接數(shù)大于最大空閑連接數(shù)了就關(guān)閉連接,設(shè)置當(dāng)前連接無(wú)效
- 如果PooledConnection無(wú)效,badConnectionCount加一,這個(gè)badConnectionCount是記錄無(wú)效的數(shù)據(jù)庫(kù)連接信息的
總結(jié)
本篇文章主要介紹了PooledConnection和PooledDataSource的pushConnection()方法,PooledConnection用到了jdk的動(dòng)態(tài)代理,生成Connection的實(shí)現(xiàn)類的代理類,攔截的邏輯中對(duì)于close()方法沒(méi)有真正關(guān)閉,而是把數(shù)據(jù)庫(kù)連接信息放入連接池中供下次再使用,數(shù)據(jù)庫(kù)連接信息放入連接池的過(guò)程是通過(guò)調(diào)用PooledDataSource的pushConnection()來(lái)完成的,具體就是從活躍連接集合中刪除這個(gè)連接,然后放入空閑連接數(shù)集合中并把當(dāng)前連接設(shè)置為無(wú)效。
到此這篇關(guān)于詳解Mybatis中的PooledDataSource的文章就介紹到這了,更多相關(guān)Mybatis PooledDataSource內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Feign調(diào)用注解組件(實(shí)現(xiàn)字段賦值功能)
這篇文章主要介紹了使用Feign調(diào)用注解組件(實(shí)現(xiàn)字段賦值功能),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
Java構(gòu)造器(構(gòu)造方法)能否可以被重寫
這篇文章主要介紹了Java構(gòu)造器(構(gòu)造方法)能否可以被重寫問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
Spring中網(wǎng)絡(luò)請(qǐng)求客戶端WebClient的使用詳解
作為替代,Spring 官方已在 Spring 5 中引入了 WebClient 作為非阻塞式 Reactive HTTP 客戶端,本文將通過(guò)樣例演示如何使用 WebClient,希望對(duì)大家有所幫助2024-04-04
springboot中使用過(guò)濾器,jsoup過(guò)濾XSS腳本詳解
這篇文章主要介紹了springboot中使用過(guò)濾器,jsoup過(guò)濾XSS腳本詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Spring-全面詳解(學(xué)習(xí)總結(jié))
這篇文章主要介紹了詳解Spring框架入門,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望能給你帶來(lái)幫助2021-07-07
詳解Spring Cloud Feign 熔斷配置的一些小坑
這篇文章主要介紹了詳解Spring Cloud Feign 熔斷配置的一些小坑,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04

