目录
缓存就是数据交换的缓冲区(称作Cache),当某一硬件要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话则从内存中找。由于缓存的运行速度比内存快得多,故缓存的作用就是帮助硬件更快地运行。
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。
SqlSession级别: 一个会话
作用域 : 一个SqlSession都有一级缓存,互不影响
优点 : 提高了程序性能,减少了数据库压力
实验一级缓存:定义两个会话,实验他们的作用域是不是一个会话级别且是否第二次查询同样的语句会不会去缓存中找。
实验一级缓存是否会生效(一级缓存默认开启无需配置)
- /**
- * 缓存测试类
- */
- public class CacheTest {
- public static void main(String[] args) {
- CacheTest cacheTest=new CacheTest();
- //1.创建一个会话:默认关闭事务
- SqlSession sqlSession = MybatisUtil.getSqlSession(true);
- //2.调用查询方法
- cacheTest.getAllUser(sqlSession);
- //调用两次:实验第二次查询会不会去缓存查
- cacheTest.getAllUser(sqlSession);
- //关闭会话
- MybatisUtil.closeSqlSession(sqlSession);
-
- }
-
- /**
- * 查询用户信息
- * @param sqlSession
- */
- public void getAllUser(SqlSession sqlSession)
- {
- //获取映射文件对应的方法:查询User 列表
- List
allUser = sqlSession.getMapper(UserMapper.class).getAllUser(); - //打印列表
- System.out.println("id\t名称\t密码");
- for (User user : allUser) {
- System.out.println(user.getId()+"\t"+user.getName()+"\t"+user.getPassword());
- }
- }
- }
实验一结果:
显而易见,一个会话中调用了两次方法,打印了两次
方法查询了两次,通过log4j可以看出该sql语句只被执行了一次,说明第二次没有去数据库再去查找(一级缓存生效)。
实验一级缓存的作用域(在一个SqlSession中)
- /**
- * 缓存测试类
- */
- public class CacheTest {
-
-
- public static void main(String[] args) {
- CacheTest cacheTest = new CacheTest();
- SqlSessionFactory build = cacheTest.getBuild();
- //创建会话1
- SqlSession sqlSession = build.openSession(false);
- System.out.println("读取会话1的数据");
- cacheTest.getAllUser(sqlSession);
- //创建会话2
- SqlSessionFactory build1 = cacheTest.getBuild();
- SqlSession sqlSession1 = build1.openSession(false);
- System.out.println("读取会话2的数据");
- cacheTest.getAllUser(sqlSession1);
- System.out.println("更新会话1的数据:");
- cacheTest.updateUser(sqlSession);
- System.out.println("读取会话1的数据");
- cacheTest.getAllUser(sqlSession);
- sqlSession.close();
- System.out.println("读取会话2的数据");
- cacheTest.getAllUser(sqlSession1);
- sqlSession1.close();
-
-
- }
- }
实验二结果:
会话1没更新前,两个会话结果都是一样,同样的sql执行了两次,因为作用域不一
- 在会话1更新后,会话2的内容还是去缓存中查询的,结果不一样,而会话1在更新后,就不会再去缓存中查找。两个会话不在一个作用域中,所以更新后也不会同步到会话2
二级缓存是SqlSessionFactory级别的,通过同一个SqlSessionFactory建造出来的SqlSession查询的数据会被缓存,此后如果再执行相同的查询语句,结果就会从缓存中获取。
作用域 : 整个应用中,会话共享
1.开启全局缓存
<setting name="cacheEnabled" value="true"/>
2.sql映射文件中设置全局配置属性:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
3.在需要使用缓存的sql语句上设置 useCache为true:
- <select id="getAllUser" resultType="user" useCache="true">
- select id,name,password from user
- select>
- 下述代码只把第二个buid删掉,共有一个即可,跟实验一的代码大同小异
- public static void main(String[] args) {
- CacheTest cacheTest = new CacheTest();
- SqlSessionFactory build = cacheTest.getBuild();
- //创建会话1
- SqlSession sqlSession = build.openSession(false);
- System.out.println("读取会话1的数据");
- cacheTest.getAllUser(sqlSession);
- //创建会话2
- SqlSession sqlSession1 = build.openSession(false);
- System.out.println("读取会话2的数据");
- cacheTest.getAllUser(sqlSession1);
- System.out.println("更新会话1的数据:");
- cacheTest.updateUser(sqlSession);
- System.out.println("读取会话1的数据");
- cacheTest.getAllUser(sqlSession);
- sqlSession.close();
- System.out.println("读取会话2的数据");
- cacheTest.getAllUser(sqlSession1);
- sqlSession1.close();
- }
- 由一个SqlSessionFactory创建出来的SqlSession之间都共享一个缓存,所以会话2也会跟着会话1所更新
使用Mybatis缓存也有一定的不方便性,比如当一级缓存失效后,数据不能随时更新。
实际开发中,尽量使用redis作为缓存工具,随时可以更新或者删除缓存中保存的数据。
二级缓存在使用时,必须需要配置才可以使用