【MyBatis】架构分析和缓存机制

1.架构图

在这里插入图片描述

1.接口层

Mybatis和数据库的交互有两种方式

  • 使用传统的MyBatis提供的API
  • 使用Mapper接口

1.1使用传统的MyBatis提供的API

这是传统的传递Statement Id和查询参数给SqlSession对象,使用SqlSession对象完成和数据库的交互;MyBatis提供了非常方便和简单的API,让用户实现对数据库的操作,和对数据库连接信息和自身信息的维护工作
在这里插入图片描述

2.Mapper接口

MyBatis 将配置文件中的每一个节点抽象为一个 Mapper 接口
在这里插入图片描述
上图就是我们开发中经常会用到的方式,将xml和mapper接口结合起来实现对数据库的操作,实现了面向接口编程和0配置

mybatis编程流程
创建 SqlSessionFactory 对象。
通过 SqlSessionFactory 获取 SqlSession 对象。
通过 SqlSession 获得 Mapper 代理对象。
通过 Mapper 代理对象,执行数据库操作。
执行成功,则使用 SqlSession 提交事务。
执行失败,则使用 SqlSession 回滚事务。
最终,关闭会话。

2.缓存机制

2.1 一级缓存

在没有配置的默认情况下,默认开启一级缓存
在这里插入图片描述
一级缓存只是相对于同一个SqlSession而言,mybatis提供了一级缓存,用来储存使用同一个SqlSession对象调用一个Mapper方法,这样的操作只执行一次,因为在SelSession第一次查询后,Mybatis就会将其存放于缓存中,下次查询直接去缓存中取结果
如何配置一级缓存呢?

<setting name="localCacheScope" value="SESSION"/>

SESSION或者STATEMENT,默认是SESSION级别,即在一个MyBatis会话中执行的所有语句,都会共享这一个缓存。一种是STATEMENT级别,可以理解为缓存只对当前执行的这一个Statement有效。
分析

  • 在会话级别下,完全相同的查询只有在第一次查询的时候会查询数据库,剩下的就是去一级缓存中取
  • 如果对数据库进行了增删改,缓存就会失效
  • 当建立两个Session时,一个Session的更新不会被另外一个Session获取,就会出现读脏数据的情况

怎么判断某两次查询是完全相同的查询?
mybatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询。

  • 传入的statementId
  • 查询时要求的结果集中的结果范围
  • 这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql() )
  • 传递给java.sql.Statement要设置的参数值
STATEMENT级别

一级缓存的脏数据
一级缓存是默认是会话级别的,当你开启2个sqlsession时,一个增删改,另外一个查询就会出现脏数据

如何配置

<setting name="localCacheScope" value="SESSION"/>
##### STATEMENT级别
如何配置
<settings>
    <setting name="localCacheScope" value="STATEMENT"/>
</settings>

STATEMENT级别的缓存,只针对当前执行的这一statement有效

总结
MyBatis一级缓存的生命周期和SqlSession一致。
MyBatis一级缓存内部设计简单,只是一个没有容量限定的HashMap,在缓存的功能性上有所欠缺。
MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement。

2.2 二级缓存

二级缓存是Application级别的缓存
在这里插入图片描述
二级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存被多个SqlSession共享,是一个全局的变量。

当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。

小结

  • MyBatis的二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,同时粒度更加的细,能够到namespace级别,通过Cache接口实现类不同的组合,对Cache的可控性也更强。
  • MyBatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。
  • 在分布式环境下,由于默认的MyBatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将MyBatis的Cache接口实现,有一定的开发成本,直接使用Redis、Memcached等分布式缓存可能成本更低,安全性也更高。

参考文章:https://tech.meituan.com/2018/01/19/mybatis-cache.html

猜你喜欢

转载自blog.csdn.net/yujing1314/article/details/107469235