MyBatis 把数据源 DataSource 分为三种:
- UNPOOLED 不使用连接池的数据源
- POOLED 使用连接池的数据源
- 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 会做以下事情:
- 初始化驱动:判断 driver 驱动是否已经加载到内存中,如果还没有加载,则会动态地加
载 driver 类,并实例化一个 Driver 对象,使用 DriverManager.registerDriver()方法将其注册
到内存中,以供后续使用。 - 创建 Connection 对象:使用 DriverManager.getConnection()方法创建连接。
- 配置 Connection 对象:设置是否自动提交 autoCommit 和隔离级别 isolationLevel。
- 返回 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()方法到底做了什么:
- 先看是否有空闲(idle)状态下的 PooledConnection 对象,如果有,就直接返回一个可用
的 PooledConnection 对象;否则进行第 2 步。 - 查看活动状态的 PooledConnection 池 activeConnections 是否已满;如果没有满,则创
建一个新的 PooledConnection 对象,然后放到 activeConnections 池中,然后返回此
PooledConnection 对象;否则进行第三步; - 看最先进入 activeConnections 池中的 PooledConnection 对象是否已经过期:如果已经
过期,从 activeConnections 池中移除此对象,然后创建一个新的 PooledConnection 对象,
添加到 activeConnections 中,然后将此对象返回;否则进行第 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 对象也是根据这它来生成的代理对象。