MyBatis缓存

1. 概念

什么是缓存:存在于内存中的临时数据

为什么是缓存:减少和数据库的交互次数,提高执行效率

适用于缓存:经常查询并且不经常改变的;数据的正确与否对最终结果影响不大的

不适用缓存:经常改变的数据;数据的正确与否对最终结果影响大:商品的库存、银行的汇率、股市的牌价

2.MyBatis一级缓存

​ 指的是Mybatis中SqlSession对象的缓存。当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供的一块区域中。该区域的结构是一个Map。当我们再次查询同样的数据,Mybatis会先去SqlSession查询中有,如果有则直接拿来用。当SqlSession对象消失时,一级缓存也消失

一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void test15(){
List<queryUserRole> Userrole = mapper.findUserRole();
System.out.println(Userrole);/*要打印地址,不要重写toString*/
List<queryUserRole> Userrole1 = mapper.findUserRole();//不发起查询,直接在缓存中取出数据
System.out.println(Userrole1);
/*清除sqlSeeion*/
session.close();
session = factory.openSession();
mapper = session.getMapper(UserDao.class);
List<queryUserRole> Userrole2 = mapper.findUserRole();//发起新的查询
System.out.println(Userrole2);
//清除缓存
session.clearCache();
List<queryUserRole> Userrole3 = mapper.findUserRole();//发起新的查询
System.out.println(Userrole3);
}

测试结果

3.MyBatis二级缓存

​ 指的是MyBatis种SqlSessionFactory对象的缓存。

由同一个SqlSessionFactory对象创建的SqlSession共享其缓存

二级缓存的使用步骤

​ 第一步:让MyBatis框架支持二级缓存(在SqlMapConfig.xml中配置)

1
2
3
4
<settings>
<!--全局性地开启或关闭所有映射器配置文件中已配置的任何缓存,默认为true-->
<setting name="cacheEnabled" value="true"></setting>
</settings>

​ 第二步:让当前的映射文件支持二级缓存(在UserDao.xml中配置), 要启用全局的二级缓存,添加一行:

​ < cache>标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。

1
2
3
<mapper namespace="cn.hxx.Dao.AccountDao">
<cache/>
</mapper>

​ 第三步:让当前的操作支持二级缓存(在select标签中配置)

1
2
3
4
<!--将 AccountDao.xml 映射文件中的<select>标签中设置 useCache=”true”代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。-->
<select id="findById" resultType="account" useCache="true">
select * from account where uid=#{id};
</select>

测试:首先开启 mybatis 的二级缓存。

​ session 去查询用户信息,查询到用户信息会将查询数据存储到二级缓存中。

​ session1 去查询用户信息,首先会去二级缓存中找是否存在数据,如果存在直接从缓存中取出数据

​ session1 删除一个用户,执行 commit 提交,将会清空该 mapper 映射下的二级缓存区域的数据

​ session1 再去查询用户信息,则需要执行sql查询数据库,并存储到二级缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void test1(){
List<Account> list = accountDao.findAll();//第一次查询,执行sql,存入二级缓存
System.out.println(list);
session.close();//关闭session,二级缓存中数据仍然在
SqlSession session1 = factory.openSession();
AccountDao session1Mapper = session1.getMapper(AccountDao.class);
List<Account> list1 = session1Mapper.findAll();//不需要执行sql,在二级缓存中可以取出
System.out.println(list1);//地址发生变化,因为在二级缓存中存储的是数据,不是地址
//删除一个用户
session1Mapper.delete(1);//执行删除,所以清空二级缓存
session1Mapper.findAll();//执行sql,并放入二级缓存
}

测试结果