mybatis的一级缓存与二级缓存


1.一级缓存

一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

Mybatis默认开启一级缓存。

一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。

@Test

public void testCache1() throws Exception{
  SqlSessionsqlSession = sqlSessionFactory.openSession();//创建代理对象
  UserMapperuserMapper = sqlSession.getMapper(UserMapper.class);

  //下边查询使用一个SqlSession

  //第一次发起请求,查询id为1的用户
  Useruser1 = userMapper.findUserById(1);
  System.out.println(user1);

  //如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

  //更新user1的信息
  user1.setUsername("测试用户22");
  userMapper.updateUser(user1);

  //执行commit操作去清空缓存
  sqlSession.commit();

  //第二次发起请求,查询id为1的用户
  Useruser2 = userMapper.findUserById(1);
  System.out.println(user2);
 
  sqlSession.close();
}

如果不commit的错误流程为:

开始执行时,开启事务,创建SqlSession对象
第一次调用mapper的方法findUserById(1)
更新数据
第二次调用mapper的方法findUserById(1),从一级缓存中取数据
aop控制 只要方法结束,sqlSession关闭 sqlsession关闭后就销毁数据结构,清空缓存
Service结束sqlsession关闭

因为上面有commmit操作,所以正确流程

开始执行时,开启事务,创建SqlSession对象
第一次调用mapper的方法findUserById(1)
更新数据
清空commit
第二次调用mapper的方法findUserById(1),从一级缓存中无数据,从数据库中取数据
aop控制 只要方法结束,sqlSession关闭 sqlsession关闭后就销毁数据结构,清空缓存
Service结束sqlsession关闭

只要是在同一个sqlssesion中,一级缓存才会生效,如果sqlssesion.commit()或者是sqlsession.close()就会清空sqlssion,一级缓存也随之消失。

2.二级缓存

二级缓存介绍
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是多个SqlSession共享的。

UserMapper有一个二级缓存区域(按namespace分,如果namespace相同则使用同一个相同的二级缓存区),其它mapper也有自己的二级缓存区域(按namespace分)。

也是就是说拥有相同的namespace的UserMapper共享一个二级缓存

开启缓存
SqlMapConfig.xml中

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

    <!-- 全局配置参数,需要时再设置 -->
    <settings>
    <!-- 开启二级缓存  默认值为true -->
    <setting name="cacheEnabled" value="true"/>
    </settings>

在UserMapper.xml中开启二缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)。

下面是开启redis缓存:

<mapper namespace="cn.mybatis.xml.mapper.UserMapper">

<!-- redis配置项 -->
<cache type="org.mybatis.caches.redis.RedisCache" /> 
    ...

至于具体的redis与mybatis的整合请参见:https://blog.csdn.net/magi1201/article/details/85635878
如何使用二级缓存

public class Userimplements Serializable {

    //Serializable实现序列化,为了将来反序列化
    // 二级缓存测试

   @Test
   public void testCache2() throws Exception {
      SqlSessionsqlSession1 = sqlSessionFactory.openSession();
      SqlSessionsqlSession2 = sqlSessionFactory.openSession();
      SqlSessionsqlSession3 = sqlSessionFactory.openSession();
  
      // 创建代理对象
      UserMapperuserMapper1 = sqlSession1.getMapper(UserMapper.class);

      // 第一次发起请求,查询id为1的用户
      Useruser1 = userMapper1.findUserById(1);
      System.out.println(user1);

      //这里执行关闭操作,将sqlsession中的数据写到二级缓存区域
      sqlSession1.close();

      //使用sqlSession3执行commit()操作
      UserMapperuserMapper3 = sqlSession3.getMapper(UserMapper.class);
      Useruser  = userMapper3.findUserById(1);
      user.setUsername("张明明");
      userMapper3.updateUser(user);
  
      //执行提交,清空UserMapper下边的二级缓存
      sqlSession3.commit();
      sqlSession3.close();

      UserMapperuserMapper2 = sqlSession2.getMapper(UserMapper.class);
  
      // 第二次发起请求,查询id为1的用户
      Useruser2 = userMapper2.findUserById(1);
      System.out.println(user2);

      sqlSession2.close();

   }
}

执行流程:

sqlsession1中使用findUserById(1)
关闭sqlsession1
sqlsession3中使用findUserById(1),从缓存中取出数据
sqlSession3.commit();
sqlSession3.close()
sqlSession2中使用findUserById(1)无法拿到数据(commit刷新二级缓存)
sqlSession2.close()

声明:半夏有你|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - mybatis的一级缓存与二级缓存


站在巨人的肩膀上,我们渺小到不可一世。