Java——Mybatis一级缓存

一、概述

当用户频繁查询某些固定的数据时,第一次将这些数据从数据库中查询出来,保存在缓存(内存,高速磁盘)中。当下次用户再次查询这些数据时,不用再通过数据库查询,而是去缓存里面查询

这么做的目的,一是提升查询速度,二是降低数据库的并发请求压力

在Mybatis中,缓存分为两种 : 一级缓存和二级缓存。而Mybatis默认开启一级缓存。

一级缓存是SqlSession级别的,二级缓存是Mapper级别的。

 

二、一级缓存

我们的请求都是由SqlSession来执行的,确切的说,应该是由DefaultSqlSession来执行的,更确切的说,其实是由DefaultSqlSession的Executor执行器来执行的。

一级缓存是针对每一个sqlSession进行缓存。每个sqlSession对象中使用HashMap存储一级缓存数据,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。

不同的sqlSession中的缓存是互相不能读取的,即不共享。

 

三、生命周期

1.MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象持有一个Executor对象,
Executor对象持有一个PerpetualCache对象;

2.第一次查询先去缓存中找是否有缓存数据,发现没有,查询数据库,将查询到的数据写入sqlsession的一级缓存区域。 

3.第二次查询先去缓存中找是否有缓存数据,发现有,直接从缓存区域中取出数据返回。 

4.当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。

SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会调用clearCache(),清空PerpetualCache对象中的数据,但是该对象仍可使用。(保证数据有效性)

 

四、存在问题

1.一级缓存并没有做粒度控制,而是在一次会话中对数据库中所有表的sql操作均做了缓存,这显然是不合理的。

2.任何更新(增、删、改)操作都会清除一级缓存,其实在有些情况下,这完全没有必要,比如两个完全不相关的表1和表2,如果你更新了表1,那为什么也要把表2的缓存也清除?

3.即便更新操作置空了当前SqlSession的一级缓存,也只是能够保证当前SqlSession的缓存失效,保证数据一致性,但是也不能保证其他SqlSession的缓存数据失效,这会导致数据不一致问题。

4.一级缓存只适用於单点,而不支持分布式部署。

5.而一级缓存的设计是每个sqlsession单独使用一个缓存空间,不同的sqlsession是不能互相访问数据的。当然,在sqlsession关闭后,其中数据自然被清空。

6.一般在mybatis集成spring时,会把SqlSessionFactory设置为单例注入到IOC容器中,不把sqlsession也设置为单例的原因是sqlsession是线程不安全的,所以不能为单例。那也就意味着其实是有关闭sqlsession的过程的。其实,对于每一个service中的sqlsession是不同的,这是通过mybatis-spring中的org.mybatis.spring.mapper.MapperScannerConfigurer创建sqlsession自动注入到service中的。 

特此警告!!!! 
当MyBatis与spring整合后,如果没有事务,一级缓存是失效的!一级缓存是失效的!一级缓存是失效的! 
原因就是两者结合后,sqlsession如果发现当前没有事务,那么每执行一个mapper方法,sqlsession就被关闭了。如果需要维持一级缓存的可用性,有两种途径:

1.添加事务

2.使用二级缓存

综合以上一级缓存存在的问题,Mybatis设计开发了二级缓存,我们将在下一篇文章中介绍。

 

参考博客:

https://blog.csdn.net/u011403655/article/details/46696065

https://blog.csdn.net/liuzhixiong_521/article/details/85063689

https://blog.csdn.net/hd243608836/article/details/78654984

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章