一级缓存

MyBatis 一级缓存、二级缓存_mybatis

@Autowired
private SqlSessionFactory sqlSessionFactory;

public void test() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //分页参数
    RowBounds rowBounds1 = new RowBounds(0, 5);
    RowBounds rowBounds2 = new RowBounds(0, 5);
    List<User> userList1 = sqlSession.selectList("com.chy.mall.dao.UserMapper.findUserByName", "张三", rowBounds1);
    //命中一级缓存,直接返回一级缓存中的对应的结果对象,不查询数据库
    List<User> userList2 = sqlSession.selectList("com.chy.mall.dao.UserMapper.findUserByName", "张三", rowBounds2);
    //true
    System.out.println(userList1 == userList2);
    sqlSession.close();
}

一级缓存的生命周期在sqlSession的生命周期之内,即在mapper方法调用的生命周期之内。

//一个sqlSession,open-> close,方法调用结束时一级缓存会被清空
userMapper.findUserByName();

//一个新的sqlSession
userMapper.findUserByName();

一级缓存默认是开启的,生命周期很短,一般不存在数据读写问题,可以放心用,但基本没啥用。

 

一级缓存的命中条件

  • 方法id相同:调用的要是同一个mapper中的同一个方法
  • 查询参数相同:传给sql语句的参数值要全部相同
select * from tb_user where id=?

不管是直接传入int型的id、Integer型的id,还是通过实体类User、Map传入的id,只要最终传给sql语句的值完全相同就行。是相同,10、10.0相等但不相同。

  • 分页参数要相同。传递的值相同即可,不要求是同一个对象。

实质是保证执行的sql语句完全相同。

 

一级缓存的生命周期

spring整合mybatis

  • 未使用事务时:每个mapper方法调用都是使用打开一个新的sqlSession,方法调用结束sqlSession被关闭。不管mapper方法调用结果如何,方法调用结束时一级缓存即被清空。
  • 使用事务时:会把这个事务中的所有mapper方法调用放在一个事务中,这些mapper方法使用同一个sqlSession,spring将sqlSession存储在ThreadLocal中,在此事务的生命周期中一直有效。不管事务执行结果如何(提交成功、回滚),只要事务结束一级缓存即被清空。
     

sqlSession调用selectXxx()方法得到结果集时写入缓存。

一级缓存被清除的几种情况

  • 调用sqlSession.clearCache()清除缓存
  • 调用sqlSession.close()关闭sqlsession
  • 调用sqlSession.commit()或sqlSession.rollback(),事务结束

 

二级缓存

MyBatis 一级缓存、二级缓存_一级缓存_02
MyBatis 一级缓存、二级缓存_mybatis_03
一级缓存是在一个sqlSession的生命周期内,二级缓存是在一个sqlSessionFactory的生命周期内,可以跨sqlSession。
 

二级缓存的工作流程
MyBatis 一级缓存、二级缓存_生命周期_04

二级缓存的命中条件

和一级缓存的命中条件相同,区别是二级缓存命中是在同一个sqlSessionFactory的生命周期内。
 

二级缓存的生命周期

  • 写入时机:sqlSession.selectXxx()查询后执行sqlSession.close()或手动调用sqlSession.commit()时。
  • 清空时机:调用mapper的增删改方法更新数据时(实质都是调用sqlSession.update()方法)
     

二级缓存的使用

  • application.properties中启用二级缓存:mybatis.configuration.cache-enabled=true
  • xml映射文件中开启二级缓存:<mapper>下加一个子标签:<cache />
  • 实体类 implements Serializable 允许序列化
     

二级缓存的清除策略

一级缓存、二级缓存都是使用map存储数据,一级缓存存在时间短,没有设置map的容量限制;二级缓存存在时间长,可在<cache />中指定map的最大容量、二级缓存清除策略,当二级缓存达到容量限制时会自动清除部分数据。

提供的清除策略如下
MyBatis 一级缓存、二级缓存_mybatis_05
 

二级缓存默认关闭,因为缓存存在时间长,容易产生脏读问题,实际基本不用,也不建议使用。

一级缓存、二级缓存的缓存粒度都是整个结果集,而非结果集中的单条记录,是以结果集为单位进行缓存。