Mybatis核心源码赏析(五)
mybatis中数据库连接池源代码
默认参数配置
protected int poolMaximumActiveConnections = 10;
protected int poolMaximumIdleConnections = 5;
protected int poolMaximumCheckoutTime = 20000;
protected int poolTimeToWait = 20000;
protected int poolMaximumLocalBadConnectionTolerance = 3;
默认最大连接数10,最小连接数5
连接池核心代码:
public void forceCloseAll() {
synchronized (state) {
expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
for (int i = state.activeConnections.size(); i > 0; i--) {
try {
PooledConnection conn = state.activeConnections.remove(i - 1);
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.");
}
}
/*** Copyright 2009-2020 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
package org.apache.ibatis.datasource.pooled;import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.logging.Logger;import javax.sql.DataSource;import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;/*** This is a simple, synchronous, thread-safe database connection pool.** @author Clinton Begin*/
public class PooledDataSource implements DataSource {private static final Log log = LogFactory.getLog(PooledDataSource.class);private final PoolState state = new PoolState(this);private final UnpooledDataSource dataSource;// OPTIONAL CONFIGURATION FIELDSprotected int poolMaximumActiveConnections = 10;protected int poolMaximumIdleConnections = 5;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;private int expectedConnectionTypeCode;public PooledDataSource() {dataSource = new UnpooledDataSource();}public PooledDataSource(UnpooledDataSource dataSource) {this.dataSource = dataSource;}public PooledDataSource(String driver, String url, String username, String password) {dataSource = new UnpooledDataSource(driver, url, username, password);expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());}public PooledDataSource(String driver, String url, Properties driverProperties) {dataSource = new UnpooledDataSource(driver, url, driverProperties);expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());}public PooledDataSource(ClassLoader driverClassLoader, String driver, String url, String username, String password) {dataSource = new UnpooledDataSource(driverClassLoader, driver, url, username, password);expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());}public PooledDataSource(ClassLoader driverClassLoader, String driver, String url, Properties driverProperties) {dataSource = new UnpooledDataSource(driverClassLoader, driver, url, driverProperties);expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());}@Overridepublic Connection getConnection() throws SQLException {return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return popConnection(username, password).getProxyConnection();}@Overridepublic void setLoginTimeout(int loginTimeout) {DriverManager.setLoginTimeout(loginTimeout);}@Overridepublic int getLoginTimeout() {return DriverManager.getLoginTimeout();}@Overridepublic void setLogWriter(PrintWriter logWriter) {DriverManager.setLogWriter(logWriter);}@Overridepublic PrintWriter getLogWriter() {return DriverManager.getLogWriter();}public void setDriver(String driver) {dataSource.setDriver(driver);forceCloseAll();}public void setUrl(String url) {dataSource.setUrl(url);forceCloseAll();}public void setUsername(String username) {dataSource.setUsername(username);forceCloseAll();}public void setPassword(String password) {dataSource.setPassword(password);forceCloseAll();}public void setDefaultAutoCommit(boolean defaultAutoCommit) {dataSource.setAutoCommit(defaultAutoCommit);forceCloseAll();}public void setDefaultTransactionIsolationLevel(Integer defaultTransactionIsolationLevel) {dataSource.setDefaultTransactionIsolationLevel(defaultTransactionIsolationLevel);forceCloseAll();}public void setDriverProperties(Properties driverProps) {dataSource.setDriverProperties(driverProps);forceCloseAll();}/*** Sets the default network timeout value to wait for the database operation to complete. See {@link Connection#setNetworkTimeout(java.util.concurrent.Executor, int)}** @param milliseconds* The time in milliseconds to wait for the database operation to complete.* @since 3.5.2*/public void setDefaultNetworkTimeout(Integer milliseconds) {dataSource.setDefaultNetworkTimeout(milliseconds);forceCloseAll();}/*** The maximum number of active connections.** @param poolMaximumActiveConnections* The maximum number of active connections*/public void setPoolMaximumActiveConnections(int poolMaximumActiveConnections) {this.poolMaximumActiveConnections = poolMaximumActiveConnections;forceCloseAll();}/*** The maximum number of idle connections.** @param poolMaximumIdleConnections* The maximum number of idle connections*/public void setPoolMaximumIdleConnections(int poolMaximumIdleConnections) {this.poolMaximumIdleConnections = poolMaximumIdleConnections;forceCloseAll();}/*** The maximum number of tolerance for bad connection happens in one thread* which are applying for new {@link PooledConnection}.** @param poolMaximumLocalBadConnectionTolerance* max tolerance for bad connection happens in one thread** @since 3.4.5*/public void setPoolMaximumLocalBadConnectionTolerance(int poolMaximumLocalBadConnectionTolerance) {this.poolMaximumLocalBadConnectionTolerance = poolMaximumLocalBadConnectionTolerance;}/*** The maximum time a connection can be used before it *may* be* given away again.** @param poolMaximumCheckoutTime* The maximum time*/public void setPoolMaximumCheckoutTime(int poolMaximumCheckoutTime) {this.poolMaximumCheckoutTime = poolMaximumCheckoutTime;forceCloseAll();}/*** The time to wait before retrying to get a connection.** @param poolTimeToWait* The time to wait*/public void setPoolTimeToWait(int poolTimeToWait) {this.poolTimeToWait = poolTimeToWait;forceCloseAll();}/*** The query to be used to check a connection.** @param poolPingQuery* The query*/public void setPoolPingQuery(String poolPingQuery) {this.poolPingQuery = poolPingQuery;forceCloseAll();}/*** Determines if the ping query should be used.** @param poolPingEnabled* True if we need to check a connection before using it*/public void setPoolPingEnabled(boolean poolPingEnabled) {this.poolPingEnabled = poolPingEnabled;forceCloseAll();}/*** If a connection has not been used in this many milliseconds, ping the* database to make sure the connection is still good.** @param milliseconds* the number of milliseconds of inactivity that will trigger a ping*/public void setPoolPingConnectionsNotUsedFor(int milliseconds) {this.poolPingConnectionsNotUsedFor = milliseconds;forceCloseAll();}public String getDriver() {return dataSource.getDriver();}public String getUrl() {return dataSource.getUrl();}public String getUsername() {return dataSource.getUsername();}public String getPassword() {return dataSource.getPassword();}public boolean isAutoCommit() {return dataSource.isAutoCommit();}public Integer getDefaultTransactionIsolationLevel() {return dataSource.getDefaultTransactionIsolationLevel();}public Properties getDriverProperties() {return dataSource.getDriverProperties();}/*** Gets the default network timeout.** @return the default network timeout* @since 3.5.2*/public Integer getDefaultNetworkTimeout() {return dataSource.getDefaultNetworkTimeout();}public int getPoolMaximumActiveConnections() {return poolMaximumActiveConnections;}public int getPoolMaximumIdleConnections() {return poolMaximumIdleConnections;}public int getPoolMaximumLocalBadConnectionTolerance() {return poolMaximumLocalBadConnectionTolerance;}public int getPoolMaximumCheckoutTime() {return poolMaximumCheckoutTime;}public int getPoolTimeToWait() {return poolTimeToWait;}public String getPoolPingQuery() {return poolPingQuery;}public boolean isPoolPingEnabled() {return poolPingEnabled;}public int getPoolPingConnectionsNotUsedFor() {return poolPingConnectionsNotUsedFor;}/*** Closes all active and idle connections in the pool.*/public void forceCloseAll() {synchronized (state) {expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());for (int i = state.activeConnections.size(); i > 0; i--) {try {PooledConnection conn = state.activeConnections.remove(i - 1);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.");}}public PoolState getPoolState() {return state;}private int assembleConnectionTypeCode(String url, String username, String password) {return ("" + url + username + password).hashCode();}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++;}}}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()) {// Pool has available connectionconn = state.idleConnections.remove(0);if (log.isDebugEnabled()) {log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");}} else {// Pool does not have available connectionif (state.activeConnections.size() < poolMaximumActiveConnections) {// Can create new connectionconn = new PooledConnection(dataSource.getConnection(), this);if (log.isDebugEnabled()) {log.debug("Created connection " + conn.getRealHashCode() + ".");}} else {// Cannot create new connectionPooledConnection oldestActiveConnection = state.activeConnections.get(0);long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();if (longestCheckoutTime > poolMaximumCheckoutTime) {// Can claim overdue connectionstate.claimedOverdueConnectionCount++;state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;state.accumulatedCheckoutTime += longestCheckoutTime;state.activeConnections.remove(oldestActiveConnection);if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {try {oldestActiveConnection.getRealConnection().rollback();} catch (SQLException e) {/*Just log a message for debug and continue to execute the followingstatement like nothing happened.Wrap the bad connection with a new PooledConnection, this will helpto not interrupt current executing thread and give current thread achance to join the next competition for another valid/good databaseconnection. At the end of this loop, bad {@link @conn} will be set as null.*/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 {// Must waittry {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 notif (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;}/*** Method to check to see if a connection is still usable** @param conn* - the connection to check* @return True if the connection is still usable*/protected boolean pingConnection(PooledConnection conn) {boolean result = true;try {result = !conn.getRealConnection().isClosed();} catch (SQLException e) {if (log.isDebugEnabled()) {log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage());}result = false;}if (result && poolPingEnabled && poolPingConnectionsNotUsedFor >= 0&& conn.getTimeElapsedSinceLastUse() > poolPingConnectionsNotUsedFor) {try {if (log.isDebugEnabled()) {log.debug("Testing connection " + conn.getRealHashCode() + " ...");}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;}/*** Unwraps a pooled connection to get to the 'real' connection** @param conn* - the pooled connection to unwrap* @return The 'real' connection*/public static Connection unwrapConnection(Connection conn) {if (Proxy.isProxyClass(conn.getClass())) {InvocationHandler handler = Proxy.getInvocationHandler(conn);if (handler instanceof PooledConnection) {return ((PooledConnection) handler).getRealConnection();}}return conn;}@Overrideprotected void finalize() throws Throwable {forceCloseAll();super.finalize();}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {throw new SQLException(getClass().getName() + " is not a wrapper.");}@Overridepublic boolean isWrapperFor(Class<?> iface) {return false;}@Overridepublic Logger getParentLogger() {return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);}}
Mybatis核心源码赏析(五)相关推荐
- Mybatis核心源码赏析(一)
Mybatis的是SpringMVC+Mybatis和数据库连接和操作的核心组件. 下面赏析一下Mybatis的核心源码包 减少我们写XML配置的mapper源代码 /** Copyright (c) ...
- Mybatis核心源码赏析(二)
我们这次只看(一)里面的的这个类. BaseMapper<T> BaseMapper<T> 继承了 Mapper<T> Mapper<T>的源码为 为什 ...
- MyBatis核心源码剖析(SqlSession XML解析 Mapper executor SQL执行过程 自定义类型处理器 缓存 日志)
MyBatis核心源码剖析 MyBatis核心源码剖析 1 MyBatis源码概述 1.1 为什么要看MyBatis框架的源码 1.2 如何深入学习MyBatis源码 1.3 源码分析的5大原则 2 ...
- Mybatis 核心源码分析
一.Mybatis 整体执行流程 二.Mybatis 具体流程源码分析 三.源码分析 写一个测试类,来具体分析Mybatis 的执行流程: public class MybatisTest {publ ...
- Android版数据结构与算法(五):LinkedHashMap核心源码彻底分析
版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 上一篇基于哈希表实现HashMap核心源码彻底分析 分析了HashMap的源码,主要分析了扩容机制,如果感兴趣的可以去看看,扩容机制那几行最难懂的 ...
- halcon区域腐蚀膨胀算子_超越halcon速度的二值图像的腐蚀和膨胀,实现目前最快的半径相关类算法(附核心源码)。...
超越halcon速度的二值图像的腐蚀和膨胀,实现目前最快的半径相关类算法(附核心源码). 发布时间:2019-03-20 12:32, 浏览次数:1259 , 标签: halcon 我在两年前的博客里 ...
- Dubbo核心源码之SPI扩展
本文来说下Dubbo核心源码之SPI扩展 文章目录 概述 Java中SPI机制详解 Dubbo SPI扩展 扩展功能介绍 扩展源码分析 ExtensionLoader初始化 配置文件扫描 扩展适配器 ...
- RocketMQ源码系列(一) NameServer 核心源码解析
目录 一.NameServer 介绍 二.NameServer 功能列表 三.NameServer 架构分析 四.NameServer 工程目录解析 五.NameServer 启动流程分析 1) 创 ...
- 新书上市 | Vue 3.0 核心源码解析,这本书给Vue学习提供新方法
Vue.js 作为一款极简的 MVVM 框架,因其轻量.易上手,得到了众多开发者的喜爱. 自从 2014 年 Vue 诞生以来,这个框架设计的初衷,尤大说只是为了设计一个让自己用起来舒服的框架,随着受 ...
最新文章
- 【4】青龙面板系列教程之QQ通知机器人XDD-plus安装
- 各样本观察值均加同一常数_对色师傅分享:如何使不同观察者在灯箱下观察的色光一致?...
- 块级元素和行内元素的区别
- 教你精确计算 I2C 上拉电阻阻值
- 3.7 ExtJS RadioGroup(单选按钮组) 使用及注意事项
- 有道口语大师APP评测:语音识别准确度低
- C# C++ 共享内存 结构体读写 结构体中嵌套结构体 结构体中带string Char*的处理方式
- SPOJ VLATTICE Visible Lattice Points 莫比乌斯反演
- DoIP诊断技术一点通
- 001.UG_NX概述
- 十大战略工具(10)—— 商业模式画布
- SHIO世硕科技马新云携全体员工:2021,在此感谢所有的一切!
- 有了域名,怎么搭建自己的网站?
- linux的的shell记忆
- 网站域名服务器加密,网站域名利用https防劫持方法
- EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式
- 风控每日一问:互联网金融产品如何利用大数据做风控?
- 视频86免费影院-视频电影网聚平台
- html插缝小游戏,HTML5游戏 - 见缝插针
- Java中long类型直接赋值大数字的问题