一般情况下我们操作数据库都是通过connection,但是频繁创建和删除connection会严重影响效率,因此在这种情况下我们一般会用到连接池,因为项目中用到的是mybatis,所以了解一下mybatis的默认的数据库连接池(大多数情况下我们会使用Durid连接池)

代码路径:

很明显看到datasource目录下有pooled和unpooled两个目录,分别是使用到了连接池和没有用到

1、unpooled目录下的UnpooledDatasource.java

/*** @author Clinton Begin* @author Eduardo Macarron*/
public class UnpooledDataSource implements DataSource {private ClassLoader driverClassLoader;private Properties driverProperties;private static Map<String, Driver> registeredDrivers = new ConcurrentHashMap<String, Driver>();//常规配置private String driver;private String url;private String username;private String password;//是否自动commit    事务的隔离级别private Boolean autoCommit;private Integer defaultTransactionIsolationLevel;//注册驱动static {Enumeration<Driver> drivers = DriverManager.getDrivers();while (drivers.hasMoreElements()) {Driver driver = drivers.nextElement();registeredDrivers.put(driver.getClass().getName(), driver);}}public UnpooledDataSource() {}public UnpooledDataSource(String driver, String url, String username, String password) {this.driver = driver;this.url = url;this.username = username;this.password = password;}//重点getconnnection  获取数据库连接,调用doGetConnection方法@Overridepublic Connection getConnection() throws SQLException {return doGetConnection(username, password);}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return doGetConnection(username, password);}//用户名  密码   设置配置private Connection doGetConnection(String username, String password) throws SQLException {Properties props = new Properties();if (driverProperties != null) {props.putAll(driverProperties);}if (username != null) {props.setProperty("user", username);}if (password != null) {props.setProperty("password", password);}return doGetConnection(props);}//真正获取连接的方法,由此可见,每次调用getConnection方法是,都会新建一个Connection对象,可想当并发量高是,数据库的连接就会被占满private Connection doGetConnection(Properties properties) throws SQLException {initializeDriver();Connection connection = DriverManager.getConnection(url, properties);configureConnection(connection);return connection;}//初始化  在调用doGetConnection方法中,会先进行一下判断,判断mybatis的configuration中是否已经有数据库驱动,没有的话会通过反射加载驱动private synchronized void initializeDriver() throws SQLException {if (!registeredDrivers.containsKey(driver)) {Class<?> driverType;try {if (driverClassLoader != null) {driverType = Class.forName(driver, true, driverClassLoader);} else {driverType = Resources.classForName(driver);}// DriverManager requires the driver to be loaded via the system ClassLoader.// http://www.kfu.com/~nsayer/Java/dyn-jdbc.htmlDriver driverInstance = (Driver)driverType.newInstance();DriverManager.registerDriver(new DriverProxy(driverInstance));registeredDrivers.put(driver, driverInstance);} catch (Exception e) {throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);}}}//设置是否自动提交   事务的隔离级别private void configureConnection(Connection conn) throws SQLException {if (autoCommit != null && autoCommit != conn.getAutoCommit()) {conn.setAutoCommit(autoCommit);}if (defaultTransactionIsolationLevel != null) {conn.setTransactionIsolation(defaultTransactionIsolationLevel);}}}

2、PolledDataSource.java类,其内部的datasource其实也是通过unpolledDataSource对象来实现的,只是在获取连接connection的时候进行了处理(重点关注getConnection方法)

public class PooledDataSource implements DataSource {private static final Log log = LogFactory.getLog(PooledDataSource.class);//PollState 充当锁对象,这个对象中也有例如  空闲连接集合,活跃链接集合,请求的数量,等一些变量private final PoolState state = new PoolState(this);//PolledDataSource中的数据源也是使用的UnpolledDataSource对象来实现的private final UnpooledDataSource dataSource;// OPTIONAL CONFIGURATION FIELDS 线程池的最大活跃数量,最大空闲数量,等待时间等等。。。protected 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;//url+username+password连接起来的字符串的hashcode值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());}//获取连接connection@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();}//线程安全的获取连接的方法(供PooledConnection中调用)  synchronizedprotected void pushConnection(PooledConnection conn) throws SQLException {//所对象为PoolStatesynchronized (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) {//如果state中空闲的连接不为空时,直接从state中的idelConnections集合中获取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 {//state中的idelConnections集合中没有连接connection了,判断活跃的connection是否小于最大活跃线程数,小于的话就新建一个connection// Pool does not have available connection if (state.activeConnections.size() < poolMaximumActiveConnections) {// Can create new connectionconn = new PooledConnection(dataSource.getConnection(), this);if (log.isDebugEnabled()) {log.debug("Created connection " + conn.getRealHashCode() + ".");}} else {//当前活跃的connection数大于最大活跃connection数是,表明不能新建connection,这种情况下,会判断是否已经超过设定的时间20s,如果超过,会根据是否自动commit,/不是自动提交,会进行rollback操作
// 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()) {//判断是否设置了自动提交,不是自动提交的话,会进行rollbacktry {oldestActiveConnection.getRealConnection().rollback();} catch (SQLException e) {/*Just log a message for debug and continue to execute the followingstatement like nothing happend.Wrap the bad connection with a new PooledConnection, this will helpto not intterupt current executing thread and give current thread achance to join the next competion 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");}  }//将之前rollback的connection进行处理,重新生成一个connection,并设置创建时间和最后使用时间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 {//当活跃connection的集合中第一个connection不符合超时,则进行等待wait// Must waittry {if (!countedWait) {state.hadToWaitCount++;countedWait = true;}//pooltimeTowait默认也是20秒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;}}}}//经过以上处理,如果conn仍然没有值,则会循环走一行流程,第二次一定会获取到conn对象(默认的超时时间是20秒,第一次已经等待过20s了)if (conn != null) {//判断conn是否能用   通过ping能否ping通// 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;}
}

3、看下创建PooledConnection对象(从上边截出的一部分代码,新建PooledConnection对象)

 // 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() + ".");}}

PooledConnection构造函数:PooledConnection函数实现了InvocationHandler接口(动态代理)

  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);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName = method.getName();//判断是否close,如果是close的话,会调用PooledDataSource中的pushConnection方法,将该conn从activeConnections删除,同时将此conn添加到idelConnections中if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {dataSource.pushConnection(this);return null;} else {try {if (!Object.class.equals(method.getDeclaringClass())) {// issue #579 toString() should never fail// throw an SQLException instead of a RuntimecheckConnection();}return method.invoke(realConnection, args);} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}}}

参考:https://blog.csdn.net/drxRose/article/details/85710850

https://www.jianshu.com/p/21cf094cb97b?open_source=weibo_search

mybatis默认的数据源连接池(PooledDataSource和UnPooledDataSource)相关推荐

  1. java was datasource_mybatis默认的数据源连接池(PooledDataSource和UnPooledDataSource)

    public classPooledDataSource implements DataSource {private static final Log log = LogFactory.getLog ...

  2. mybatis开启log_mybatis使用spring-druid数据源连接池配置log4j打印sql语句以及开启监控平台...

    杂七杂的杂 作为程序员,开发工程中,一套利于测试或者监控的工具很重要,mybatis默认没有提供log4j的打印sql语句的配置. 这对于开发rest服务,提供接口的开发者而言,是在很不好做,再加上m ...

  3. springboot添加多数据源连接池并配置Mybatis

    springboot添加多数据源连接池并配置Mybatis 转载请注明出处:https://www.cnblogs.com/funnyzpc/p/9190226.html May 12, 2018  ...

  4. 使用MyBatis集成阿里巴巴druid连接池(不使用spring)

    在工作中发现mybatis默认的连接池POOLED,运行时间长了会报莫名其妙的连接失败错误.因此采用阿里巴巴的Druid数据源(码云链接 ,中文文档链接). mybatis更多数据源参考博客链接 . ...

  5. 性能优化之数据库和数据源连接池配置

    什么?!数据库连接拿不到? 今天在公司对系统进行压测,由于我的sit和dev和uat环境都是用的用的是一个数据库服务器,我让用户在的sit进行压测,分别是单线程测试,并发测试,但是用户一开始测,我的三 ...

  6. mybatis,mysql,datasource,dpcb连接池的关系

    datasource是配置数据源,顾名思义就是数据的来源,在数据源中可以配置数据是从何而来,可以是mysql,也可以是oracle,所以可以如下配置 <beanid="dataSour ...

  7. DBCP数据源连接池实现原理分析

    前些天在调试公司系统的时候发现这样的一个问题:mysql数据库服务停止一段时间后再次重启后吗,tomcat服务无法请求数据库服务,调试了半天对这个问题进行定位解决,期间也搞了很多有关mysql数据库的 ...

  8. JDBC数据源连接池(1)---DBCP

    何为数据源呢?也就是数据的来源.我在前面的一篇文章<JDBC原生数据库连接>中,采用了mysql数据库,数据来源于mysql,那么mysql就是一种数据源.在实际工作中,除了mysql,往 ...

  9. jndi weblogic mysql_Tomcat配置JNDI数据源连接池

    [Tomcat数据源连接池加密] Tomcat 5.0.28 Jndi配置: 1)部署你的应用到Tomcat,并且确保能正常访问. 2)进放admin控制台,如果你无法进入控制台,请参考常用的一些Ja ...

最新文章

  1. Stylus插件开发教程
  2. Loadrunner的Tuxedo脚本分析,基本流程和基本函数介绍
  3. 697. Degree of an Array 频率最高元素的最小覆盖子数组
  4. 用实验验证神经网络的节点是否可以看作弹性小球
  5. 个人学习Linux决心书
  6. docker 开发常用命令总结
  7. scss-!optional
  8. 异常处理汇总-服务器系列
  9. java中地图查询比较慢,在java中缓慢的地图
  10. python数值类型教程_Python数值类型 int、float、complex 详解
  11. Win7 可以下载python最高什么版本?
  12. 安卓系统的电视机_天猫魔盒强刷机教程,把天猫魔盒刷成安卓系统教程?
  13. cdr添加节点快捷键_cdr怎么添加节点 在CDR X8怎么给曲线添加节点图文教程
  14. 不擅长演讲?值得技术收藏的PPT演讲底层逻辑--大树模型
  15. 从“站在巨人的肩上”到“跪到侏儒之脚下”——图灵公司副主编自供(二)...
  16. 将Excel中的矩阵变成列表
  17. 矩阵旋转(翻转)刷题总结
  18. 计算机附近组件的安装方法,在计算机上安装组件
  19. java反射的作用于原理、初学者
  20. bookxnote手机版_BookxNote

热门文章

  1. PHP中的des加密类
  2. 编程语言发展的编年史
  3. 为什么要importmodulepython_python – 为什么“import”这样实现?
  4. 计算机教学反思博,博文25教学反思
  5. 二 用标准c语言实现hanoi塔问题,天大2016年1二月《数据结构》期末大作业考核要求.doc...
  6. c++的string转char*遇到的指针问题
  7. c/c++格式化字符串的标识
  8. 平流式初沉池贮砂斗计算_除磷药剂如何投加效果最好?投加量如何计算?
  9. 桌面鼠标手写输入法_「桌面分享」工作娱乐两不误,花费7万打造的桌面都有些啥?...
  10. java chinapay_通过PHP/Java Bridge来实现ecshop的chinapay支付接口