一级缓存
在mybatis中一级缓存是默认开启的,它以sqlsession’为单位,多个sqlsession的缓存相互独立,互不干扰
一级缓存的生命周期
- MyBatis 在开启一个数据库会话时,会创建一个新的 SqlSession 对象,SqlSession 对象中
会有一个新的 Executor 对象。Executor 对象中持有一个新的 PerpetualCache 对象;当会
话结束时,SqlSession 对象及其内部的 Executor 对象还有 PerpetualCache 对象也一并释
放掉。 - 如果 SqlSession 调用了 close()方法,会释放掉一级缓存 PerpetualCache 对象,一级缓存
将不可用。 - 如果 SqlSession 调用了 clearCache(),会清空 PerpetualCache 对象中的数据,但是该对象
仍可使用。 - SqlSession 中执行了任何一个 update 操作(update()、delete()、insert()) ,都会清空
PerpetualCache 对象的数据,但是该对象可以继续使用
简而言之,mybatis在面临查询时,会查找一级缓存中是否有相同的查询条件,若有则从缓冲池中拿数据,没有则从数据库中查找,并将结果存储在一级缓存中
如何判断查询是否相同
-
传入的 statementId。
-
查询时要求的结果集中的结果范围。
-
这次查询所产生的最终要传递给 Preparedstatement 的 Sql 语句字符串。
-
传递的参数
根据以上四个条件可以判断查询是否相同,但其实简单来说根据statementId和传递参数就能判断查询条件是否相同
一级缓存可能出现的问题
我们知道,一级缓存的缓冲池是以sqlsession为单位的,当多个sqlsession存在时,若一个sqlsession改变了一条记录,而另一个sqlsession在修改前已经将该记录存放在缓冲池中,此时缓冲池的数据已经跟数据库的真实数据不一样了。
所以一级缓存无法保证数据的实时性。
二级缓存
二级缓存是以sqlsessionFactory为单位的,每个mapper的namespace对应一个cache,可以使用cache-ref让多个mapper指向同一个cache,下面会解释为什么要这样做
注意:执行commit或close的时候才会将一级缓冲的数据同步到二级缓存,sqlsession在二级缓存中查不到该数据会去一级缓存中查找,再不行才会查找数据库
二级缓存的作用
我们知道,一级缓存的作用范围是sqlsession,若其它sqlsession将数据进行更改后而当前的sqlsession未能及时察觉,查询出来的数据已经不是真实数据了,二级缓存的作用就是让多个sqlsession能够相互通信,避免上述情况的发生。
下面给出一些情况
1. 当多个sqlsession从二级缓存中查询数据时,一个sqlsession对其修改后,其它sqlsession也能及时更新
SqlSession session = factory.openSession();
SqlSession session2 = factory.openSession();
SqlSession session3 = factory.openSession();
StuMapper mapper = session.getMapper(StuMapper.class);
StuMapper mapper2 = session2.getMapper(StuMapper.class);
StuMapper mapper3 = session3.getMapper(StuMapper.class);
//往二级缓冲池中放数据
Student student = mapper.selById2(1);
System.out.println(student);
session.commit();
System.out.println("-----------------------------------------------");
//从二级缓存中拿数据
Student student2 = mapper2.selById2(1);
System.out.println(student2);
System.out.println("-----------------------------------------------");
//清空该mapper对应的二级缓存池
mapper.updStu(1,"cx");
session.commit();
//重新从数据库查询数据
Student student3 = mapper3.selById2(1);
System.out.println(student3);
System.out.println("-----------------------------------------------");
2. 当查询涉及到多表连接时,其中一张表对应的mapper执行DML操作,而另一个mapper对应的二级缓存池不会清空,除非将两个mapper的namespace绑定为同一个
SqlSession session = factory.openSession();
SqlSession session2 = factory.openSession();
SqlSession session3 = factory.openSession();
StuMapper mapper = session.getMapper(StuMapper.class);
StuMapper mapper2 = session2.getMapper(StuMapper.class);
StuMapper mapper3 = session3.getMapper(StuMapper.class);
ClaMapper claMapper = session.getMapper(ClaMapper.class);
Student student = mapper.selById2(1);
System.out.println(student);
//更新班级名称
claMapper.updateCla(1,"web");
session.commit();
Student student2 = mapper2.selById2(1);
System.out.println(student2);
session2.commit();
Student student3 = mapper3.selById2(1);
System.out.println(student3);
Student student4 = mapper3.selById2(1);
System.out.println(student4);
session3.commit();
Student student5 = mapper2.selById2(1);
System.out.println(student5);
在ClaMapper中加上<cache-ref namespace=“com.xie.stuMapper”>后
这样做有利有弊,利是能够更好的保证数据的实时性,弊端则是增大了检测的力度,使得缓存更容易被清空,降低了效率