发布时间:2022-12-01 文章分类:编程知识 投稿人:王小丽 字号: 默认 | | 超大 打印

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

缓存(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修改后的数据。所以验证了一级缓存只在数据库会话内部共享

小结:

Mybatis二级缓存

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

开启二级缓存具体步骤:

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

工作机制

小结:

总结:

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

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

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