MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以对配置和原生Map使用简单的XML或注解,将接口和Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
其次是Mybatis的几个核心概念。
- SqlSession : 代表和数据库的一次会话,向用户提供了操作数据库的方法。
- MappedStatement: 代表要发往数据库执行的指令,可以理解为是Sql的抽象表示。
- Executor: 具体用来和数据库交互的执行器,接受MappedStatement作为参数。
- 映射接口: 在接口中会要执行的Sql用一个方法来表示,具体的Sql写在映射文件中。
- 映射文件: 可以理解为是Mybatis编写Sql的地方,通常来说每一张单表都会对应着一个映射文件,在该文件中会定义Sql语句入参和出参的形式。
Mybatis提供了一级缓存的方案来优化在数据库会话间重复查询的问题。实现的方式是每一个SqlSession中都持有了自己的缓存,一种是SESSION级别,即在一个Mybatis会话中执行的所有语句,都会共享这一个缓存。一种是STATEMENT级别,可以理解为缓存只对当前执行的这一个statement有效。如果用一张图来代表一级查询的查询过程的话,可以用下图表示。
从Local Cache获数据,不需要执行sql查询
一级缓存配置
上文介绍了一级缓存的实现方式,解决了什么问题。在这个章节,我们学习如何使用Mybatis的一级缓存。只需要在Mybatis的配置文件中,添加如下语句,就可以使用一级缓存。共有两个选项,SESSION或者STATEMENT,默认是SESSION级别。
<setting name="localCacheScope" value="SESSION"/>
我们可以看到,sqlSession2更新了id为1的学生的姓名,从凯伦改为了小岑,但session1之后的查询中,id为1的学生的名字还是凯伦,出现了脏数据,也证明了我们之前就得到的结论,一级缓存只存在于只在数据库会话内部共享。
一级缓存工作流程&源码分析
这一章节主要从一级缓存的工作流程和源码层面对一级缓存进行学习。
client 发送select 请求给sql Session,然后调用对应的cacheExecutor执行,从cache中获取,没有获取就查询数据库
Executor: SqlSession向用户提供操作数据库的方法,但和数据库操作有关的职责都会委托给Executor。
通过DefaultSqlSessionFactory开启一个SqlSession,创建SqlSession的过程中,会通过Configuration创建一个Executor
默认的为SimpleExecutor
根据MappedStatement的id,sql的offset,sql的limit,sql本身和sql的参数,来构造cacheKey
Statement Id + Offset + Limmit + Sql + Params
query方法执行的最后,会判断一级缓存级别是否为statement级别,如果是,就清空缓存,所以statement级别的一级缓存无法共享localCache
- Mybatis一级缓存的生命周期和SqlSession一致。
- Mybatis的缓存是一个粗粒度的缓存,没有更新缓存和缓存过期的概念,同时只是使用了默认的hashmap,也没有做容量上的限定。
- Mybatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,有操作数据库写的话,会引起脏数据,建议是把一级缓存的默认级别设定为Statement,即不使用一级缓存。
二级缓存介绍
在上文中提到的一级缓存中,其最大的共享范围就是一个SqlSession内部,那么如何让多个SqlSession之间也可以共享缓存呢,答案是二级缓存。 当开启二级缓存后,会使用CachingExecutor装饰Executor,在进入后续执行前,先在CachingExecutor进行二级缓存的查询,具体的工作流程如下所示
在二级缓存的使用中,一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存是被多个SqlSession共享着的,是一个全局的变量。 当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。
验证Mybatis的二级缓存不适应用于映射文件中存在多表查询的情况。一般来说,我们会为每一个单表创建一个单独的映射文件,如果存在涉及多个表的查询的话,由于Mybatis的二级缓存是基于namespace的,多表查询语句所在的namspace无法感应到其他namespace中的语句对多表查询中涉及的表进行了修改,引发脏数据问题。
二级缓存,使用了cachingExecutor,实现了缓存的查询和写入
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
调用BaseExecutor里面的doUpdate执行sql语句
调用executor包里面SimpleStatementHandler 执行
调用statement的execute方法执行sql语句,最终执行结果返回执行成功的条数
MapperProxy 代理 通过invoke调用方法,来执行sqlSession
转载:https://blog.csdn.net/kuaipao19950507/article/details/102383336