MyBatis 执行流程
读取 MyBatis 配置文件:mybatis-config.xml 加载运行环境和映射文件
构造会话工厂 SqlSessionFactory
会话工厂创建 SqlSession 对象(包含了执行 SQL 语句的所有方法)
操作数据库的接口,Executor 执行器,同时负责查询缓存的维护
Executor 接口的执行方法中有一个 MappedStatement 类型的参数,封装了映射信息
输入参数映射
输出结果映射
延迟加载
MyBatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询。在 MyBatis 配置文件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false。主要原理:使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 a.getB().getName() ,拦截器 invoke() 方法发现 a.getB() 是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 a.getB().getName() 方法的调用。
MyBatis 缓存
一级缓存:基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当Session 进行 flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存
二级缓存:基于 namespace 和 mapper 的作用域起作用的,不是依赖于 SQL session,默认也是采用 PerpetualCache,HashMap 存储。需要单独开启,一个是核心配置,一个是mapper 映射文件
对于缓存数据更新机制,当某一个作用域(一级缓存 Session /二级缓存 Namespaces )的进行了新增、修改、删除操作后,默认该作用域下所有 select 中的缓存将被 clear。二级缓存需要缓存的数据实现 Serializable 接口,只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中。
Executor 执行器
MyBatis 有三种基本的 Executor 执行器:
SimpleExecutor: 每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象。
ReuseExecutor: 执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map<String, Statement>内,供下一次使用。简言之,就是重复使用 Statement 对象。
BatchExecutor:执行 update(没有 select,JDBC 批处理不支持 select),将所有 sql 都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理。与 JDBC 批处理相同。
分页插件
MyBatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内存分页,而非物理分页;
可以在 sql 内直接书写带有物理分页的参数来完成物理分页功能;
可以使用分页插件来完成物理分页。
分页插件的基本原理是使用 MyBatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的 sql,然后重写 sql,根据 dialect 方言,添加对应的物理分页语句和物理分页参数。
xml 常见标签
除了常见的增删改查外,还有<resultMap>、 <parameterMap>、 <sql>、 <include>、 <selectKey> ,加上动态 sql 的 9 个标签, trim|where|set|foreach|if|choose|when|otherwise|bind 等,其中 <sql> 为 sql 片段标签,通过 <include> 标签引入 sql 片段, <selectKey> 为不支持自增的主键生成策略标签。