mybatis缓存机制

mybatis缓存机制

  • mybatis 缓存分为一级缓存和二级缓存,那这两级缓存是怎么实现的呢?

  • 他们的存储结构,作用范围,失效场景是什么?

1.1 缓存是什么?

缓存存在于内存中的临时数据,访问速度比一般随机存取存储器(RAM)快的一种高速存储器

  • 为什么使用缓存:

    • 减少和数据库交互的次数,提高执行效率

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

  • 适用于缓存:

    • 经常改变的数据。

    • 数据的正确与否对最终结果影响很大的。

      • 例如:商品的库存,银行的汇率,股市的牌价

1.2 Mybatis中的一级缓存和二级缓存

一级缓存:

  • 它是mybatis中sqlSession对象的缓存,当我们执行查询之后,查询的结果会同时存入到SqlSession提供一块区域中

  • 该区域的结构是一个Map,当我们再次查询同样的数据,Mybatis会先去SqlSession中查询是否有,有的话直接拿出来用

  • 当SqlSession对象消失时,mybatis的一级缓存也就消失了

  • mybatis缓存机制_第1张图片

一级缓存实现方式

@Test
public void findTest() throws IOException {
    //调用utils里面的getsqlSession 包含提交操作
    SqlSession session = MybatisUtils.getSqlSession(true);
    UserDao mapper = session.getMapper(UserDao.class);
    //第一次
    System.out.println("第一次");
    List<User> all = mapper.findAll();
    System.out.println(all.get(0));
    System.out.println("第二次");
    List<User> all2 = mapper.findAll();
    System.out.println(all.get(0));System.out.println("比较两个对象是否一样");
    System.out.println(all.equals(all2));//释放资源
    MybatisUtils.closeSqlSession(session);
}

mybatis缓存机制_第2张图片

清空缓存的方法:

    session.clearCache();//此方法也可以清空缓存

mybatis缓存机制_第3张图片

查看结果:

mybatis缓存机制_第4张图片

1.3 一级缓存失效场景

一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存

//第一次
System.out.println("第一次");
List<User> all = mapper.findAll();
System.out.println(all.get(0));
User user=new User();
user.setId(3);
user.setUsername("程序员爱什么?");
mapper.update(user);System.out.println("第二次");
List<User> all2 = mapper.findAll();
System.out.println(all.get(0));
System.out.println("第三次");
List<User> all3 = mapper.findAll();
System.out.println(all.get(0));System.out.println("比较两个对象是否一样");
System.out.println(all.equals(all2));

mybatis缓存机制_第5张图片

测试缓存关闭失效场景:

@Test
    public void IuserTest() throws IOException {//获取sqlsession 对象
        System.out.println("第一次加载");
        SqlSession session = MyBatisUtils.getSqlSession(true);
        IuserMapper mapper = session.getMapper(IuserMapper.class);
        List<User> all = mapper.findAll();
        System.out.println(all.get(0));
        //在这个位置关闭就会报错
       // session.close();System.out.println("第二次加载");
        SqlSession session2 = MyBatisUtils.getSqlSession(true);
        IuserMapper mapper2 = session.getMapper(IuserMapper.class);
        List<User> all2 = mapper2.findAll();
        System.out.println(all2.get(0));
        User user=new User();
        user.setId(13);
        user.setUsername("程序员");
        user.setSex("女");
        user.setAddress("爱代码否?爱money");
        user.setBirthday(Date.valueOf("2023-03-15"));
        mapper2.update(user);
​
        session2.commit();
        session2.close();
        System.out.println("第三次加载");
        SqlSession session3 = MyBatisUtils.getSqlSession(true);
        IuserMapper mapper3 = session.getMapper(IuserMapper.class);
        List<User> all3 = mapper3.findAll();
        System.out.println(all3.get(0));System.out.println("对象比较");
        System.out.println(mapper==mapper2);
        System.out.println(mapper2==mapper3);
        session3.close();
    }

1.4 二级缓存

  • 二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

  • 他指的是SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存

原理解析

mybatis 二级缓存也是通过PerpetualCache 缓存对象存储的,所以存储结构也是基于HashMap的
二级缓存是基于mapper文件的namespace 的,多个SqlSession 可以共享一个mapper 中的二级缓存区域

mybatis缓存机制_第6张图片

一个sqlSession 会将执行的结果保存到二级缓存区,其他的SqlSession在获取的时候,不会从数据库获取数据,而是从缓存中获取数据。但是最终得到的对象是不相等的,因为二级缓存中缓存的是数据,而不是对象。 当其中有一个SqlSession 执行了事物提交操作,就会清空二级缓存,导致二级缓存失效,其他的SqlSession 想要获取数据,需要从新从数据库取。

1.4.1 开启二级缓存

实现步骤:

第一步:

在核心配置文件中配置:

<configuration>
    
    <properties resource="jdbc.properties"/>
    
    <settings>
        <setting name="cacheEnabled" value="true"/>
    settings>
    
  • cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。

    • 为 true 代表开启二级缓存;

    • 为 false 代表不开启二级缓存。

第二步 mapper配置文件:


<cache eviction="FIFO" flushInterval="60000" size="5120" readOnly="true" />
<select id="findAll" resultType="user" useCache="true">
        select * from T_user
    select>

映射文件中的标签中设置 useCache=”true”代表当前这个 select要使用二级缓存,如果不使用二级缓存可以设置为 false。

注意: 针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。

使用缓存的时候,最好给实体类序列化一下:implements Serializable

测试代码:

@Test
public void findcahe() throws IOException {
    //调用utils里面的getsqlSession 包含提交操作SqlSession session1 = MybatisUtils.getSqlSession(true);
    UserDao mapper1 = session1.getMapper(UserDao.class);
    SqlSession session2 = MybatisUtils.getSqlSession(true);
    UserDao mapper2 = session2.getMapper(UserDao.class);
    //第一次
    System.out.println("第一次");
    List<User> user1 = mapper1.findAll();
    System.out.println(user1.get(0));
    session1.close();System.out.println("第二次");
    List<User> user2 = mapper2.findAll();
    System.out.println(user2.get(0));
    session2.close();System.out.println("比较两个对象是否一样");
    System.out.println("测试是否相等"+(user2==user1));}

mybatis缓存机制_第7张图片

注解的使用方式:

@CacheNamespace(eviction = FifoCache.class, flushInterval = 60000, size = 1024, readWrite = true)
    @Select("select * from T_user") @Options(useCache = true)
    public List<User> findAll();

你可能感兴趣的:(Mybatis持久层框架技术,mybatis,缓存,java)