2018-11-06 10:52

  我们来分析一下,MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。本文将从以下几个方面介绍:

  相关文章

  前言

  类图

  工厂类实现

  数据库连接实现

  连接池的实现

  从连接池中获取连接(流程图)

  把连接放入到连接池中(流程图)

  相关文章

  Mybatis 解析配置文件的源码解析

  Mybatis 类型转换源码分析

  前言

  在使用 Mybatis 的时候,数据库的连接一般都会使用第三方的数据源组件,如 C3P0,DBCP 和 Druid 等,其实 Mybatis 也有自己的数据源实现,可以连接数据库,还有连接池的功能,下面就来看看 Mybatis 自己实现的数据源头和连接池的一个实现原理。

  类图

  Mybatis 数据源的实现主要是在 datasource 包下:

  


  我们常见的数据源组件都实现了 Javax.sql.DataSource 接口,Mybatis 也实现该接口并且提供了两个实现类 UnpooledDataSource 和 PooledDataSource 一个使用连接池,一个不使用连接池,此外,对于这两个类,Mybatis 还提供了两个工厂类进行创建对象,是工厂方法模式的一个应用,首先来看下它们的一个类图:

  


  关于上述几个类,PooledDataSource 和 UnpooledDataSource 是数据源实现的主要逻辑,代码比较复杂,放在后面来看,现在先看看看两个工厂类 。

  DataSourceFactory

  先来看看 DataSourceFactory 类,该类是 JndiDataSourceFactory 和 UnpooledDataSourceFactory 两个工厂类的顶层接口,只定义了两个方法,如下所示:

  1541467756441608.png

  UnpooledDataSourceFactory

  UnpooledDataSourceFactory 主要用来创建 UnpooledDataSource 对象,它会在构造方法中初始化 UnpooledDataSource 对象,并在 setProperties 方法中完成对 UnpooledDataSource 对象的配置

  

  JndiDataSourceFactory 依赖 JNDI 服务器中获取用户配置的 DataSource,这里可以不看。

  PooledDataSourceFactory

  PooledDataSourceFactory 主要用来创建 PooledDataSource 对象,它继承了 UnpooledDataSource 类,设置 DataSource 参数的方法复用UnpooledDataSource 中的 setProperties 方法,只是数据源返回的是 PooledDataSource 对象而已。

 1541468216999327.png

  以上这些就是 Mybatis 用来创建数据源的工厂类,下面就来看下数据源的主要实现。

  UnpooledDataSource

  UnpooledDataSource 不使用连接池来创建数据库连接,每次获取数据库连接时都会创建一个新的连接进行返回;

  1541468853411843.png

  接下来看下获取连接的方法:

 1541469015159539.png

  以上代码就是 UnpooledDataSource 类的主要实现逻辑,每次获取连接都是从数据库新创建一个连接进行返回,又因为,数据库连接的创建是一个耗时的操作,且数据库连接是非常珍贵的资源,如果每次获取连接都创建一个,则可能会造成系统的瓶颈,拖垮响应速度等,这时就需要数据库连接池了,Mybatis 也提供了自己数据库连接池的实现,就是 PooledDataSource 类。

  PooledDataSource

  PooledDataSource 是一个比较复杂的类,PooledDataSource 新创建数据库连接是使用 UnpooledDataSource 来实现的,且 PooledDataSource 并不会管理 java.sql.Connection 对象,而是管理 PooledConnection 对象,在 PooledConnection 中封装了真正的数据库连接对象和其代理对象;此外,由于它是一个连接池,所以还需要管理连接池的状态,比如有多少连接是空闲的,还可以创建多少连接,此时,就需要一个类来管理连接池的对象,即 PoolState 对象;先来看下 PooledDataSource 的一个 UML 图:

  


  PooledConnection

  先来看看 PooledConnection 类,它主要是用来管理数据库连接的,它是一个代理类,实现了 InvocationHandler 接口,

  1541469183408598.png

  接下来看下 invoke 方法,该方法是 proxyConnection 这个连接代理对象的真正代理逻辑,它会对 close 方法进行代理,并且在调用真正的连接之前对连接进行检测。

  1541469278565672.png

  PoolState

  PoolState 类主要是用来管理连接池的状态,比如哪些连接是空闲的,哪些是活动的,还可以创建多少连接等。该类中只是定义了一些属性来进行控制连接池的状态,并没有任何的方法。

  1541469496898495.png

  PooledDataSource 它是一个简单的,同步的,线程安全的数据库连接池

  知道了 UnpooledDataSource 用来创建数据库新的连接,PooledConnection 用来管理连接池中的连接,PoolState 用来管理连接池的状态之后,来看下 PooledDataSource 的一个逻辑,该类中主要有以下几个方法:获取数据库连接的方法 popConnection,把连接放回连接池的方法 pushConnection,检测数据库连接是否有效的方法 pingConnection ,还有 关闭连接池中所有连接的方法 forceCloseAll,接下来就来看看这几个方法是怎么实现,在看之前,先看下该方法定义的一些属性:

  1541469607841161.png

  接下来看下从数据库连接池中获取连接的实现逻辑:

  从 连接池中获取连接的方法主要是在 popConnection 中实现的,先来看下它的一个流程图:

  


  代码逻辑如下:

  1541469923343913.png

        

  以上就是从连接池获取连接的主要逻辑。

  现在来看下当执行 close 方法的时候,会把连接放入的连接池中以供下次重新使用,把连接放入到连接池中的方法为 pushConnection 方法,它也是 PooledDataSource 类的一个主要方法,先来看下它的流程图:

  


  代码如下:

  1541471014274108.png

  以上代码就是把不用的连接放入到连接池中以供下次使用,

  在上面两个方法中,都调用了 isValid 方法来检测连接是否可用,该方法除了检测 valid 字段外,还会调用 pingConnection 方法来尝试让数据库执行测试 SQL 语句,从而检测真正的数据库连接对象是否依然正常可用。

  1541470812373525.png

  总结

  在连接池中提到了 连接池中的最大连接数和最大空闲数,在 获取连接和把连接放入连接池中都有判断,

  1. 获取连接:首先从连接池中进行获取,如果连接池中已经没有空闲的连接了,则会判断当前的活跃连接数是否已经达到允许的最大值了,如果没有,则还可以创建新的连接,之后把它放到活跃的集合中进行使用,如果当前活跃的已达到最大值,则阻塞。

  2.返还连接到连接池,在返还连接的时候,进行判断,如果空闲连接数已达到允许的最大值,则直接关闭真正的数据库连接,否则把该连接放入到空闲集合中以供下次使用。

  Mybatis 数据源中,主要的代码逻辑还是在连接池类 PooledDataSource 中,对于获取连接的方法 popConnection,返还连接的方法 pushConnection ,需要结合上图来看,才能看得清楚。

  如果你对我说的感兴趣,那可以关注一下我发的文章,如果你有朋友也对 Mybatis感兴趣,也可以转发给他们,邀请他们一起拉学习。

  原文出处:陈树义


评论