CommonDataSource数据池的定义是在jdk库中,是对数据源概念的抽象顶层,指定了数据源必须实现的方法。

一、非线程池实现方式:UnpooledDataSource

概述一下其链接的过程如下图:

springboot mybatis mysql连接池 mybatis数据库连接池原理_mybatis

如何创建一个连接:

 

 

二、线程池方式维护链接:

使用线程池可以减少频繁创建、销毁线程带来的性能损害。通过配置各种参数保证系统在实际的应用中有更好的负载和性能之间获得更好的实践。

Mybatis提供了一个简单的连接池,主要分析一下这个class:org.apache.ibatis.datasource.pooled.PooledDataSource

1、配置部分:

 - 基础默认参数

protected int poolMaximumActiveConnections = 10;    //激活线程池最大数
  protected int poolMaximumIdleConnections = 5;       //空闲线程池最大数
  protected int poolMaximumCheckoutTime = 20000;      //最长的保持链接时间
  protected int poolTimeToWait = 20000;               //没有可用conn的时候,等待时间
  protected int poolMaximumLocalBadConnectionTolerance = 3;//有多少个badConn最大数

- 配置类:PoolState

基础控制线程池的参数、连接表都在这里来维护;

protected long requestCount = 0;                    //conn被使用次数,请求次数
  protected long accumulatedRequestTime = 0;          //累计签发线程所需的时间
  protected long accumulatedCheckoutTime = 0;         //累计conn链接时间
  protected long claimedOverdueConnectionCount = 0;   //回收超期conn的次数
  protected long accumulatedCheckoutTimeOfOverdueConnections = 0;  //超期线程累计使用多长时间
  protected long accumulatedWaitTime = 0;               //等待签发conn累计等候时间
  protected long hadToWaitCount = 0;                    //无有效的conn,需要等候的次数
  protected long badConnectionCount = 0;                //bad链接数

2、两个关键的方法

1、popConnection/pushConnection:如下图

1)取出:在需要数据链接的时候会请求connection,调用popConnection;

2)归还:在处理完之后需要将conn归还线程池,调用pushConnection

3、细节

1)问:为什么所有的线程都要判断是不是AutoCommit,并要RollBack?

   在JDBC通过Connection管理事务的,默认会自动提交事务。也可以手工关闭,同构commit方法提交,通过rollBack进行回滚。

所以,每次释放连接的时候都要判断如果自动提交被关闭了,则后续断开的时候需要RollBack。

   rollBack一般会判断是否已经关闭连接,如果连接还没有close,则会撤销事务内所有的变更,并释放数据库锁。

 

2)问:为啥旧的连接,要设置为无效,重新包装一个newPoolConnection?

因为PoolConnection是在实际的连接基础上重新加上了线程池所需要的属性,比如

private final int hashCode;
  private final PooledDataSource dataSource;  //连接池属性
  private final Connection realConnection;    //实际连接
  private final Connection proxyConnection;
  private long checkoutTimestamp;     //保持连接的时间
  private long createdTimestamp;      //创建时间
  private long lastUsedTimestamp;     //最有一次使用时间
  private int connectionTypeCode;     //连接类型编码
  private boolean valid;              //状态标识(新建时为true)

 

3)问:invalidate具体是怎么样的?被设置为invalidate的线程最后哪里去了

invalidate会将PoolConnection的属性valid设置为false,后续不会被用于任何地方, 垃圾回收将其回收掉。

 

4)问:如何判断连接时isValidate()

判断3个条件,

  • valid的属性是否为true——在Conn初始化的时候设为true
  • realConnection是否为null
  • pingConnection:需要确认这个Conn是否能联通,这个过程是什么呢?
  • 首先判断是不是closed
  • 如果监测到线程池ping开关是否打开,如果没有打开直接返回;
  • 创建一个Statement,然后执行固定的Query语句——NO PING QUERY SET
  • 如果不报错,则返回true

5)问:conn要设置ConnectionTypeCode,这个作用什么?

conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));

这个适用于生成这个连接的HashCode(poolConnection的属性)来标识每个连接的的唯一性