天天看点

MyBatis数据源与连接池

MyBatis 把数据源 DataSource 分为三种:

  1. UNPOOLED 不使用连接池的数据源
  2. POOLED 使用连接池的数据源
  3. JNDI(Java Naming and Directory Interface ) 使用 JNDI 实现的数据源

创建数据源

MyBatis 是通过工厂模式来创建数据源 DataSource 对象的,MyBatis 定义了抽象的工厂接

口:org.apache.ibatis.datasource.DataSourceFactory,通过其 getDataSource()方法返回数据源

DataSource。

上述三种不同类型的 type,则有对应的以下 dataSource 工厂:

  • POOLED PooledDataSourceFactory
  • UNPOOLED UnpooledDataSourceFactory
  • JNDI JndiDataSourceFactory

Connection 创建

当我们需要创建 SqlSession 对象并需要执行 SQL 语句时,这时候 MyBatis 才会去调用

dataSource 对象来创建 java.sql.Connection 对象。

也就是说,java.sql.Connection 对象的创

建一直延迟到执行 SQL 语句的时候

Unpooled

当 的 type 属性被配置成了”UNPOOLED”,MyBatis 首先会实例化一个

UnpooledDataSourceFactory 工 厂 实 例 , 然 后 通 过 .getDataSource() 方 法 返 回 一 个

UnpooledDataSource 实例对象引用,我们假定为 dataSource。

使用 UnpooledDataSource 的 getConnection(),每调用一次就会产生一个新的 Connection 实

例对象。

UnpooledDataSource 会做以下事情:

  1. 初始化驱动:判断 driver 驱动是否已经加载到内存中,如果还没有加载,则会动态地加

    载 driver 类,并实例化一个 Driver 对象,使用 DriverManager.registerDriver()方法将其注册

    到内存中,以供后续使用。

  2. 创建 Connection 对象:使用 DriverManager.getConnection()方法创建连接。
  3. 配置 Connection 对象:设置是否自动提交 autoCommit 和隔离级别 isolationLevel。
  4. 返回 Connection 对象。

Pooled

PooledDataSource 将 java.sql.Connection 对 象 包 裹 成 PooledConnection 对 象 放 到 了

PoolState 类型的容器中维护。MyBatis 将连接池中的 PooledConnection 分为两种状态: 空闲状态(idle) 和 活动状态(active),这两种状态的 PooledConnection 对象分别被存储到PoolState 容器内的 idleConnections 和 activeConnections 两个 List 集合中:

idleConnections:

空闲(idle)状态 PooledConnection 对象被放置到此集合中,表示当前闲置的

没有被使用的 PooledConnection 集合,调用 PooledDataSource 的 getConnection()方法时,

会优先从此集合中取 PooledConnection 对象。当用完一个 java.sql.Connection 对象时,

MyBatis 会将其包裹成 PooledConnection 对象放到此集合中。

activeConnections:

活 动 (active) 状 态 的 PooledConnection 对 象 被 放 置 到 名 为

activeConnections 的 ArrayList 中,表示当前正在被使用的 PooledConnection 集合,调用

PooledDataSource 的 getConnection() 方 法 时 , 会 优 先 从 idleConnections 集 合 中 取 PooledConnection 对象,如果没有,则看activeConnections集合是否已满,如果未满,PooledDataSource 会创建出一个 PooledConnection,添加到此集合中,并返回。

popConnection()方法到底做了什么:
  1. 先看是否有空闲(idle)状态下的 PooledConnection 对象,如果有,就直接返回一个可用

    的 PooledConnection 对象;否则进行第 2 步。

  2. 查看活动状态的 PooledConnection 池 activeConnections 是否已满;如果没有满,则创

    建一个新的 PooledConnection 对象,然后放到 activeConnections 池中,然后返回此

    PooledConnection 对象;否则进行第三步;

  3. 看最先进入 activeConnections 池中的 PooledConnection 对象是否已经过期:如果已经

    过期,从 activeConnections 池中移除此对象,然后创建一个新的 PooledConnection 对象,

    添加到 activeConnections 中,然后将此对象返回;否则进行第 4 步。

  4. 线程等待

当我们的程序中使用完 Connection 对象时,如果不使用数据库连接池,我们一般会调用

connection.close()方法,关闭 connection 连接,释放资源。

我们希望当 Connection 使用完后,调用.close()方法,而实际上 Connection 资源并没有被释

放,而实际上被添加到了连接池中。

这里要使用代理模式,为真正的 Connection 对象创建一个代理对象,代理对象所有的方法

都是调用相应的真正 Connection 对象的方法实现。当代理对象执行 close()方法时,要特殊

处理,不调用真正 Connection 对象的 close()方法,而是将 Connection 对象添加到连接池中。

MyBatis 的 PooledDataSource 的 PoolState 内部维护的对象是 PooledConnection 类型的对

象,而 PooledConnection 则是对真正的数据库连接 java.sql.Connection 实例对象的包裹器。

PooledConenction 实现了 InvocationHandler 接口,并且 proxyConnection 对象也是根据这它来生成的代理对象。

继续阅读