【Mybatis系列】Mybatis缓存

在学习mybatis缓存之前我们先来看三个问题:

  • 什么是缓存: 

       存在内存的临时数据

       将用户经常查询的数据放在缓存(内存)中,用户查询数据就不会用磁盘(关系型数据库数据文件)查询,从缓存中查询,从而提高了查询效率,解决高并发系统的性能问题

  • 为什么要使用缓存?

       减少和数据库的交互次数,减少系统开销,提高系统的效率

  • 什么样的数据能使用缓存?

        经常查询,并且不经常修改的数据

Mybatis缓存:

       MyBatis包含一个非常强大的查询缓存特性,可以非常方便得定制和配置缓存,缓存可以极大的提升查询效率

       MyBatis系统中默认定义了两级缓存: 一级缓存和二级缓存

       默认情况下只有一级缓存开启,(sqlsession级别的缓存,也称为本地缓存)

       二级缓存需要手动开启和配置,是基于namespace级别的缓存

       为了提高扩展性,MyBatis定义了缓存接口Cache

一级缓存:

特点:

扫描二维码关注公众号,回复: 11991541 查看本文章
  1.   一级缓存也叫本地缓存:
  2. · 与数据库同一次会话期间查询到的数据会放在本地缓存中。
  3. · 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;

//根据id查询用户
User queryUserById(@Param("id") int id);
<select id="queryUserById" resultType="user">
  select * from user where id = #{id}
</select>
@Test
public void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
---------------------------------------------------------------------------------
   UserMapper mapper = session.getMapper(UserMapper.class);
 
   User user = mapper.queryUserById(1);
   System.out.println(user);
   User user2 = mapper.queryUserById(1);
   System.out.println(user2);
   System.out.println(user==user2);
 --------------------------------------------------------------------
   session.close();
}

结果分析:

我们可以看到是同一个sqlSession  执行了两次相同的查询,但是通过日志我们只能看到执行了一条SQL语句,说明第一条是通过数据库查询的,第二条是通过缓存查询的

一级缓存失效的四种情况: 

1.sqlSession不同:

@Test
public void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
   SqlSession session2 = MybatisUtils.getSession();
   UserMapper mapper = session.getMapper(UserMapper.class);
   UserMapper mapper2 = session2.getMapper(UserMapper.class);
 
   User user = mapper.queryUserById(1);
   System.out.println(user);
   User user2 = mapper2.queryUserById(1);
   System.out.println(user2);
   System.out.println(user==user2);
 
   session.close();
   session2.close();
}

结果: 发现发送了两条sql语句,每个sqlSession中的缓存相互独立

2.sqlSession相同,查询条件不同

@Test
public void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
   UserMapper mapper = session.getMapper(UserMapper.class);
   UserMapper mapper2 = session.getMapper(UserMapper.class);
 
   User user = mapper.queryUserById(1);
   System.out.println(user);
   User user2 = mapper2.queryUserById(2);
   System.out.println(user2);
   System.out.println(user==user2);
 
   session.close();
}

3.sqlSession相同,两次查询之间执行了增删改操作: 

增加方法
//修改用户
int updateUser(Map map);
编写SQL
<update id="updateUser" parameterType="map">
  update user set name = #{name} where id = #{id}
</update>
测试
@Test
public void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
   UserMapper mapper = session.getMapper(UserMapper.class);
 
   User user = mapper.queryUserById(1);
   System.out.println(user);
 
   HashMap map = new HashMap();
   map.put("name","kuangshen");
   map.put("id",4);
   mapper.updateUser(map);
 
   User user2 = mapper.queryUserById(1);
   System.out.println(user2);
 
   System.out.println(user==user2);
 
   session.close();
}

观察结果:查询在中间执行了增删改操作后,重新执行了

结论:因为增删改操作可能会对当前数据产生影响

4.sqlSession相同,手动清除一级缓存:

@Test
public void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
   UserMapper mapper = session.getMapper(UserMapper.class);
 
   User user = mapper.queryUserById(1);
   System.out.println(user);
 
   session.clearCache();//手动清除缓存
 
   User user2 = mapper.queryUserById(1);
   System.out.println(user2);
 
   System.out.println(user==user2);
 
   session.close();
}

二级缓存:

二级缓存又称为全局缓存,由于一级缓存的作用域太低,所以诞生了二级缓存,基于namespace级别的缓存,一个名称控件,对应一个二级缓存:

工作机制:

一个会话查询一条数据-----> 这个数据被放在当前会话的一级缓存中------->如果当前会话关闭了------->这个会话的一级缓存就没了-------> 这个时候一级缓存的数据就会被保存到二级缓存中,新的会话内容就可以从二级缓存中获取内容

如何使用?

在mybatis-config.xml中开启全局缓存

<setting name="cacheEnabled" value="true"/>

在每个mapper.xml配置中使用二级缓存:

<cache/>

代码测试:

@Test
public void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
   SqlSession session2 = MybatisUtils.getSession();
 
   UserMapper mapper = session.getMapper(UserMapper.class);
   UserMapper mapper2 = session2.getMapper(UserMapper.class);
 
   User user = mapper.queryUserById(1);
   System.out.println(user);
   session.close();
 
   User user2 = mapper2.queryUserById(1);
   System.out.println(user2);
   System.out.println(user==user2);
 
   session2.close();
}

结论

· 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据

· 查出的数据都会被默认先放在一级缓存中

· 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中

缓存的原理图:

猜你喜欢

转载自blog.csdn.net/qq_30631063/article/details/108233988