Mybatis

零散的一些知识

  • mybatis中生成对应的映射接口对象使用了java原生的动态代理实现的
  • mybatis执行sql的过程

缓存

  • 一级缓存
    • 一级缓存位于SqlSession中,每个SqlSession中持有了Executor,每个Executor中有一个LocalCache。当用户发起查询时,MyBatis根据当前执行的语句生成MappedStatement,在Local Cache进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入Local Cache,最后返回结果给用户。
    • 对一级缓存的操作其实就是对一个hashMap进行操作,key是由MappedStatement的Id、SQL的offset、SQL的limit、SQL本身以及SQL中的参数构成
    • 配置:开发者只需在MyBatis的配置文件中,添加如下语句,就可以使用一级缓存。共有两个选项,SESSION或者STATEMENT,默认是SESSION级别,即在一个MyBatis会话中执行的所有语句,都会共享这一个缓存。一种是STATEMENT级别,可以理解为缓存只对当前执行的这一个Statement有效。有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement。
      1
      <setting name="localCacheScope" value="SESSION"/>
  • 二级缓存
    • 如果多个SqlSession之间需要共享缓存,则需要使用到二级缓存。开启二级缓存后,会使用CachingExecutor装饰Executor,进入一级缓存的查询流程前,先在CachingExecutor进行二级缓存的查询,具体的工作流程如下所示。

      img

    • 二级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存被多个SqlSession共享,是一个全局的变量。

    • MyBatis的二级缓存不适应用于映射文件中存在多表查询的情况。通常我们会为每个单表创建单独的映射文件,由于MyBatis的二级缓存是基于namespace的,多表查询语句所在的namspace无法感应到其他namespace中的语句对多表查询中涉及的表进行的修改,引发脏数据问题。为了解决脏数据的问题,可以使用Cache ref,让ClassMapper引用StudenMapper命名空间,但这样做使缓存的粒度变粗了,多个Mapper namespace下的所有操作都会对缓存使用造成影响。

    • 配置:

      • <****setting**** name=”cacheEnabled” value=”true”/>
      • 在MyBatis的映射XML中配置cache或者 cache-ref 。cache标签用于声明这个namespace使用二级缓存,并且可以自定义配置。
        • type:cache使用的类型,默认是PerpetualCache,这在一级缓存中提到过。
        • eviction: 定义回收的策略,常见的有FIFO,LRU。
        • flushInterval: 配置一定时间自动刷新缓存,单位是毫秒。
        • size: 最多缓存对象的个数。
        • readOnly: 是否只读,若配置可读写,则需要对应的实体类能够序列化。
        • blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。
      • cache-ref代表引用别的命名空间的Cache配置,两个命名空间的操作使用的是同一个Cache。
    • 在分布式环境下,由于默认的MyBatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将MyBatis的Cache接口实现,有一定的开发成本,直接使用Redis、Memcached等分布式缓存可能成本更低,安全性也更高。

Mybatis流程图

加载配置文件到开启会话的流程

  • image-20210305153125143

MapperProxy的构建流程

  • image-20210305153210865

Executor执行流程

  • image-20210305153400110

Mybatis
https://x-leonidas.github.io/2022/02/01/11技术栈/Mybatis/
作者
听风
发布于
2022年2月1日
更新于
2022年5月5日
许可协议