一、前言
SqlSessionFactory 是创建 SqlSession 对象的工厂,单例,在应用程序中有且仅有一个实例对象。SqlSession 是暴露给用户的调用数据库查询接口的 API,该对象 非线程安全。因此,每个线程应使用不同的 SqlSession 对象。当然,Mybatis 也提供内置的线程安全的类 org.apache.ibatis.session.SqlSessionManager (内部是使用 ThreadLocal 保证线程安全)。
二、SqlSessionFactory
2.1 API 及继承关系
2.1.1 API

所定义的接口大多数是重载方法 openSession ,也就是获取 SqlSession 会话。
接口参数大致包括:
- 是否自动提交。
- 数据库连接对象
Connection。 - 执行器类型,分别有 SIMPLE(默认执行器类型)、REUSE、BATCH。
事务隔离级别,分别有 NONE、READ_COMMITED、READ_UNCOMMITTED、REPEATABLE_READ、SERIALIZABLE。
2.1.2 继承关系

DefaultSqlSessionFactory:Mybatis 默认实现。SqlSessionManager- 内部持有
SqlSessionFactory对象和本地线程变量ThreadLocal<SqlSession>,即每个线程拥有同一个SqlSession对象,通过它构建的SqlSession对象是线程安全的。而DefaultSqlSessionFactory所构建的SqlSession对象是非线程安全。 SqlSessionManagement同时实现SqlSession接口,拥有执行 Sql 查询能力。在用户调用执行时,通过动态代理从ThreadLocal<SqlSession>变量中获取对应线程的 SqlSession,并执行相应的方法。
- 内部持有
简单来说,SqlSessionManager 是一个 SqlSession 管理器,通过它的 API 调用会保证所使用的 SqlSession 线程安全。
2.2 SqlSessionFactory 如何生产 SqlSession 对象?
SqlSessionFactory 获取 SqlSession 对象核心代码如下。获取步骤为:
- 从配置环境中获取环境对象(配置文件解析全局配置标签
<environment>)。 - 根据配置环境获取事务工厂。
- 利用反射生成事务对象(一般为
JdbcTransaction, 当与 Spring 框架整合,为ManagedTransaction)。 - 根据事务以及执行类型获取执行器(默认执行器为 SIMPLE, 所以获得 SimpleExecutor)。
- 生成的对象统一用 DefaultSqlSession 进行包装并返回。
三、SqlSession
SqlSession 是 Mybatis 工作的主要 API 接口,通过这些接口你拥有执行命令、获取 mappers 以及管理事务的能力。
3.1 API

该接口定义了与数据库相关的增、删、改、查等一系列接口,还包含了事务开启/关闭/回滚等操作。
还有一个非常重要的接口 getMapper(Class) 获取经过 JDK 动态代理 Mapper 接口的代理类对象。
该接口的默认实现类只有一个DefaultSqlSession 。
下面我们简单分析 SqlSession 在 Mybatis 执行 SQL 链路中是承担哪些职责。
3.2 SqlSession 承担的职责
通过源码分析,SqlSession 关于 SELECT|UPDATE|DELETE|INSERT 等API 其他做的内容大致相同,
- 从配置类中获取
MappedStatement对象,该对象包含 Mapper 文件所定义的一切内容,比如 SQL 语句,参数对象、结果对象、类型处理器等等。 - 交给
Executor执行器执行数据库查询。
以 selectOne(String, object, RowBounds) API 进行简要分析。
selectOne() API
这个接口不接收任何 SQL 参数,是最简单的 SQL 查询 API。
由于selectOne() 也是 selectList() 的其中一种情况,最终会调用下面这个方法: 
有意思的是,其他操作 DELETE 、INSERT 都是调用 UPDATE API 执行: 
至于 Excutor 到底如何执行 SQL ,后续会分析。
3.3 getMapper(Class)
我们可以对 getMapper(Class) API 做一个细致的分析,因为我们都知道在使用 Mybatis 框架进行编程时,需要同时编写 Mapper 接口类和与之相对应的 Mapper 映射文件,我们只需要通过 getMapper(Class) 就通过所定义的接口实现类并执行相应的方法,Mybatis 就能帮助我们查询数据库并返回相应的类型/集合等数据体。我们也知道,Mybatis 是通过 JDK 动态代理完成这一工作,那下面,我们就通过源码的方式过一遍基本流程。
两个阶段
Mybatis 初始化。解析 Mybatis 配置文件、Mapper 映射文件、Mapper接口。XMLMapperBuilder#bindMapperForNamespace()方法根据 Mapper 文件的namespace获取 Class 实例,通过configuration.addMapper(Class)方法注册到MapperRegistry对象中。此时并未进行动态代理。
getMapper(Class) 调用。- 根据类型获取
MapperProxyFactory(里面包含对应 Class 引用),调用MapperProxyFactory#newInstance进行动态代理。
- 根据类型获取
源码片段一
- 从缓存中获取 MapperFactory 工厂类,该类用来创建 Mapper 接口代理对象。
- 通过工厂类创建 Mapper 接口的代理类。当我们获取到 Mapper 对象时,实际上是代理对象。
那对于代理对象而言,我们就应该着重看他的 InvocationHandler 方法,实现类是 org.apache.ibatis.binding.MapperProxy 。
MapperProxy
MapperProxy 实现 JDK java.lang.reflect.InvocationHandler 重要的是它的 invoke() 方法。
源码片段二
MapperMethodInvoker
MapperMethodInvoker 接口代理是写在 MapperProxy 类里面的,它有两个实现类,继承关系如下: 
两者区别是: 如果当前方法是被 default 关键字标识,则创建 DefaultMethodInvoker 对象,否则,创建 PlainMethodInvoker 。
我们看一个 PlainMethodInvoker 都做了些什么?
里面持有 MapperMethod 对象,由它代理完成 SQL 的执行。
看到了熟悉的 SELECT|DELETE 等方法,最终还是交给 SqlSession 对象完成 SQL 的执行。
四、总结
SqlSessionFactory解析全局配置文件并存入Connfiguration对象中,这里面包含了 Mybatis 的一切。SqlSession是 Mybatis 暴露给用户调用增、删、改、查的 API 接口,它是非线程安全的,但是SqlSessionManager使用ThreadLocal变量给用户提供了一个线程安全的SqlSession管理器,并且实现了SqlSession接口,因为也有了查询的能力。SqlSession做的事情并不多,都是委托给执行器执行。getMapper(Class)是核心接口,当调用 Mapper 接口定义的方法时,Mybatis 框架通过动态代理底层执行连接获取、参数封装、数据库查询、结果集处理、类型转换等一系列流程。

