詳解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()方法沒有真正關(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)文章
Spring中@Configuration注解的使用場(chǎng)景
這篇文章主要介紹了Spring中@Configuration注解的使用場(chǎng)景,@Configuration注解是從Spring?3.0版本開始加入的一個(gè)使Spring能夠支持注解驅(qū)動(dòng)開發(fā)的標(biāo)注型注解,主要用于標(biāo)注在類上,需要的朋友可以參考下2023-11-11RabbitMQ交換機(jī)與Springboot整合的簡(jiǎn)單實(shí)現(xiàn)
這篇文章主要介紹了RabbitMQ交換機(jī)與Springboot整合的簡(jiǎn)單實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07springboot 如何設(shè)置端口號(hào)和添加項(xiàng)目名
這篇文章主要介紹了springboot設(shè)置端口號(hào)和添加項(xiàng)目名的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08詳解Java編程規(guī)約(命名風(fēng)格、常量定義、代碼格式)
這篇文章主要介紹了詳解Java編程規(guī)約(命名風(fēng)格、常量定義、代碼格式),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-10-10Spring Boot整合RabbitMQ實(shí)例(Topic模式)
Topic Exchange 轉(zhuǎn)發(fā)消息主要是根據(jù)通配符。接下來(lái)通過(guò)本文給大家分享Spring Boot整合RabbitMQ實(shí)例(Topic模式),需要的朋友參考下吧2017-04-04Java Socket編程心跳包創(chuàng)建實(shí)例解析
這篇文章主要介紹了Java Socket編程心跳包創(chuàng)建實(shí)例解析,具有一定借鑒價(jià)值,需要的朋友可以參考下2017-12-12Java Netty HTTP服務(wù)實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了Java Netty HTTP服務(wù)實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08Spring Boot 集成Shiro的多realm實(shí)現(xiàn)以及shiro基本入門教程
這篇文章主要介紹了Spring Boot 集成Shiro的多realm實(shí)現(xiàn)以及shiro基本入門,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10