首页IT科技mybatis的缓存级别(Mybatis缓存机制)

mybatis的缓存级别(Mybatis缓存机制)

时间2025-05-02 14:41:08分类IT科技浏览4759
导读:什么是缓存? 为什么使用缓存? 什么场景下使用缓存?...

什么是缓存? 为什么使用缓存? 什么场景下使用缓存?

缓存(Cache)就是数据交换的缓冲区           ,一个临时存储数据的地方                 ,当我们读取数据时会首先从缓存中查找需要的数据      ,如果找到了则直接执行     ,找不到的话再从内存中找           。

在实际开发中                 ,我们会经常对数据库进行数据查询           ,而从数据库读取数据的效率是非常低下的     ,并且频繁地去访问数据库会增大数据库压力降低数据库查询性能等                 ,所以我们可以将经常查询且不经常改变的数据保存到缓存中(缓存就是内存中的一个对象)           ,这样用户在查询的时候就不用到数据库中查询(磁盘),从而减少与数据库的交付次数                 ,从而提高查询效率                 ,解决了高并发系统的性能问题                 。

缓存的本质就是用空间换时间,牺牲数据的实时性           ,以服务器内存中的数据暂时代替从数据库读取最新的数据                 ,减少数据库IO      ,减轻服务器压力           ,减少网络延迟                 ,从而提高访问速度      。

Mybatis的缓存机制

Mybatis一级缓存(sqlSession级别)

​ 一级缓存是SqlSession级别的缓存      ,在操作数据库时需要构造SqlSession对象     ,在对象中有一个 数据结构(HashMap) 用于存储缓存数据                 ,不同的SqlSession之间的缓存数据区域(HashMap)互不影响           。

​ 当在同一个sqlSession (会话) 中执行两次相同的SQL语句时           ,第一次执行完毕会将从数据库中查询的数据写到缓存(内存)     ,第二次查询时会从缓存中获取数据                 ,不再去底层数据库查询           ,从而提高查询效率                。需要注意的是,如果sqlSession执行了DML操作(insert           、update                 、delete)                 ,并提交到数据库                 ,MyBatis则会清空sqlSession中的一级缓存,这样做的目的是为了保证缓存中存储的是最新的信息           ,避免出现脏读现象      。

MyBatis默认开启一级缓存                 ,不需要进行任何配置      ,当一个sqlSession结束后该sqlSession的一级缓存也就不在了           ,一级缓存是不能关闭的      。

测试说明:

​ 我们可以创建一张学生表                 ,写sql查询语句根据id查询学生信息      ,定义一个方法     ,在方法内调用三次该查询                 ,提前开启日志打印方便我们在控制台查看打印的sql语句           ,我们可以看到     ,只有第一次打印了sql语句也就是真正查询了数据库                 ,后面的查询使用了一级缓存           ,直接在缓存中读取的数据并没有访问数据库                。

​ 我们接着对上面的数据进行测试,从上面我们可以知道学生表中的数据已经存入到缓存中                 ,接下来我们可以对数据进行(增/删/改)测试(insert      、update           、delete)                 ,再进行查询           。可以发现进行了增                、删      、改操作后控制台打印了后面的查询sql语句,也就是再次访问了数据库进行查询           ,所以清空了一级缓存导致失效了      。

​ 我们继续测试                 ,这次我们开启两个SqlSession(会话)      ,在SqlSession1中我们进行查询操作从而开启一级缓存           ,在SqlSession2我们可以进行(增/删/改)操作                 ,再用SqlSession1去查询      ,可以发现出现了脏数据     ,SqlSession1并没有查询到SqlSession2修改后的数据                 。所以验证了一级缓存只在数据库会话内部共享

小结:

一级缓存(本地缓存), 作用域默认为sqlSession           。当 Session flush 或 close 后, 该Session 中的所有Cache 将被清空。

本地缓存不能被关闭, 但可以调用clearCache()来清空本地缓存, 或者改变缓存的作用域                 。

在mybatis3.1之后                 ,可以配置本地缓存的作用域           ,在 mybatis.xml 中配置                 。

让一级缓存失效的几种情况:

① 不同的SqlSession对应不同的一级缓存

② 同一个SqlSession但是查询条件不同

③ 同一个SqlSession的两次查询期间执行了增删改操作

④ 同一个SqlSession的两次查询期间手动清空了缓存

Mybatis二级缓存

二级缓存也叫全局缓存     ,一级缓存作用域太低了                 ,二级缓存默认是全局开启的           ,它是基于namespace级别的缓存,一个名称空间                 ,对应一个二级缓存                 ,所以也称之为“namespace缓存           ”,需要在配置SQL语句的XML中添加节点           , 以表示当前XML中的所有查询都允许开通二级缓存                 ,并且      ,在节点上配置useCache=“true                 ”           ,则对应的节点的查询结果将被二级缓存处理                 ,并且      ,此查询返回的结果的类型必须是实现了Serializable接口的     ,如果使用了配置如何封装查询结果                 ,则必须使用节点来封装主键的映射           ,满足以上条件后     ,二级缓存将可用                 ,只要是当前namespace中查询出来的结果           ,都会根据所执行的SQL语句及参数进行 结果的缓存

开启二级缓存后,会使用CachingExecutor装饰Executor                 ,进入一级缓存的查询流程前                 ,先在CachingExecutor进行二级缓存的查询。 二级缓存开启后,同一个namespace下的所有操作语句           ,都影响着同一个Cache                 ,即二级缓存被多个SqlSession共享      ,是一个全局的变量           。 当开启缓存后           ,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库                 。

开启二级缓存具体步骤:

在mybatis-config.xml文件中开启缓存

<setting name="cacheEnabled"value="true"/> <!-- 全局配置参数                 ,需要时再设置 --> <settings> <!-- 开启二级缓存 默认值为true --> <setting name="cacheEnabled" value="true"/> </settings>

在mapper.xml配置文件中使用二级缓存

type:cache使用的类型      ,默认是PerpetualCache     ,这在一级缓存中提到过      。 eviction: 定义回收的策略                 ,常见的有FIFO           ,LRU           。 flushInterval: 配置一定时间自动刷新缓存     ,单位是毫秒                。 size: 最多缓存对象的个数      。 readOnly: 是否只读                 ,若配置可读写           ,则需要对应的实体类能够序列化      。 blocking: 若缓存中找不到对应的key,是否会一直blocking                 ,直到有对应的数据进入缓存                。 <!--在当前Mapper.xml文件中使用二级缓存--> <mapper namespace="cn.hpu.mybatis.mapper.UserMapper"> <!-- 开启本mapper namespace下的二级缓存 --> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/> <cache/>

也可以直接在mapper.xml文件中加入,但是要记得实体类要序列化                 ,不然容易会报Caused by: java.io.NotSerializableException: com.xsq.pojo.User异常

在实体类中实现序列化:

public class User implements Serializable { //Serializable实现序列化,为了将来反序列化 }

工作机制

一个会话查询一条数据           ,这个数据就会被放在当前会话的一级缓存中; 如果当前会话关闭了                 ,这个会话对应的一级缓存就没了      ,但是我们想要的是           ,会话关闭了                 ,一级缓存中的数据被保存到二级缓存中; 新的会话被查询信息      ,就可以从二级缓存中获取内容; 不同的mapper查出的数据会放在自己对应的缓存(map)中;

小结:

只要开启了二级缓存     ,在同一个Mapper文件下就有效; 所有的数据都会先放在一级缓存中; 只有当会话提交                 ,或者关闭的时候           ,才会提交到二级缓存中           。

总结:

MyBatis一级缓存的生命周期和SqlSession一致      。 MyBatis一级缓存内部设计简单     ,只是一个没有容量限定的HashMap                 ,在缓存的功能性上有所欠缺                 。 MyBatis的一级缓存最大范围是SqlSession内部           ,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据                 ,建议设定缓存级别为Statement           。 MyBatis的二级缓存相对于一级缓存来说                 ,实现了SqlSession之间缓存数据的共享,同时粒度更加的细           ,能够到namespace级别                 ,通过Cache接口实现类不同的组合      ,对Cache的可控性也更强。 MyBatis在多表查询时           ,极大可能会出现脏数据                 ,有设计上的缺陷      ,安全使用二级缓存的条件比较苛刻                 。 在分布式环境下     ,由于默认的MyBatis Cache实现都是基于本地的                 ,分布式环境下必然会出现读取到脏数据           ,需要使用集中式缓存将MyBatis的Cache接口实现     ,有一定的开发成本                 ,直接使用Redis,Memcached等分布式缓存可能成本更低           ,安全性也更高                 。

无论是一级缓存还是二级缓存,只要数据发生了写操作(增      、删                、改)                 , 缓存数据都将被自动清理

由于Mybatis的缓存清理机制过于死板                 ,所以,一般在开发实践中并不怎么使用!更多的是使用其它的缓存工具并自行制定缓存策略

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
surface3投屏电视(微软Surface Pro 3笔记本U盘重装系统win7详细图文步骤) 系统盘如何重装系统win7(系统盘怎么重装系统?使用系统盘重装系统的详细图文教程)