mybatis的二级缓存_mybatis的一级缓存

mybatis的二级缓存_mybatis的一级缓存上次谈到了mybatis一级缓存实际上是SqlSession级别的缓存,多个SqlSession并不共享,针对这种情况,我们可以使用mybatis二级缓存来处理。1.mybatis二级缓存是什么mybatis二级缓存是mybatis的另一种缓存机制,区别于一级缓存,它是namespace级别,即一个mapper一个缓存,相互独立,互不影响。默认不开启,需要配置开启。同一namespace下的多个sqlSession可以共享缓存,大体结构如下图2.二级缓存生效的条件同一个namespa.

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

上次谈到了 mybatis一级缓存实际上是SqlSession级别的缓存,多个SqlSession并不共享,针对这种情况,我们可以使用mybatis二级缓存来处理。

1.mybatis二级缓存是什么

mybatis二级缓存是mybatis的另一种缓存机制,区别于一级缓存,它是namespace级别,即一个mapper一个缓存,相互独立,互不影响。默认不开启,需要配置开启。同一namespace下的多个sqlSession可以共享缓存,大体结构如下图

在这里插入图片描述

2.二级缓存生效的条件

  1. 同一个namespace下
  2. 同一个查询方法
  3. 同一个方法参数

需要注意的是二级缓存需要配置,一共有两种方式,下面分开讲解,举例中涉及到的表结构为用户表user(id,username,age)

1)xxxMapper.java文件上直接配置@CacheNamespace

@CacheNamespace
public interface UserMappser { 
   

    @Select("select * from user where id = #{id}")
    User selectById(Integer id);

    @Update("update user set username = #{username} where id = #{id}")
    int updateById(@Param("id") Integer id, @Param("username") String username);

}

测试用例 这里需要注意下,我们模拟多个SqlSession查询,所以不需要增加事务,否则同一事务下是共用一个SqlSession的

	@Test
    public void test(){ 
   
        User user = userMappser.selectById(1);
        System.out.println(user);

        User user1 = userMappser.selectById(1);
        System.out.println(user1);

        System.out.println(user == user1);
    }

结果集

在这里插入图片描述
这里可以看到中间的红框提示我们已经命中缓存,只查询了一次,但是看两个对象比较竟然是false,这里是因为二级缓存的配置readWrite默认是true,这里大家可以理解为是否拷贝,如果改为readWrite=false就是引用,那么两个实体比较就会为true,但是如果采用readWrite=false会导致严重的数据错乱,建议还是默认为好


xxxMapper.xml文件中配置

我们这使用的是spring boot 整合mybatis,只需要在xxxMapper.xml配置文件中增加一个属性cache

<mapper namespace="com.linggong.mybatis.UserMappser">

    <cache/>

    <select id="selectByIdXml" resultType="com.linggong.mybatis.User">
        select * from user where id = #{id}
    </select>
</mapper>

测试类

	@Test
    public void test2(){ 
   
        User user = userMappser.selectByIdXml(1);
        System.out.println(user);

        User user1 = userMappser.selectByIdXml(1);
        System.out.println(user1);

        System.out.println(user == user1);
    }

结果集

在这里插入图片描述


需要注意的是@CacheNamespace或者xml中的cache元素只能二选其一,如果都配置的话启动会报错

单个方法的二级缓存设置可以在使用@CacheNamespace时在方法上配置@Options或者使用xml时配置select元素属性

3.@CacheNamespace注解属性

进入到CacheNamespace中我们可以看到它有如下属性
在这里插入图片描述

  • implementation —缓存实现 Cache接口 实现类
  • eviction —缓存算法
  • flushInterval —缓存有效时间(毫秒),默认为0一直有效,不为0的话会在调用链上增加一层ScheduledCache,在putObject和getObject前执行下面的代码
 @Override
  public void putObject(Object key, Object object) { 
   
    clearWhenStale();
    delegate.putObject(key, object);
  }

  @Override
  public Object getObject(Object key) { 
   
    return clearWhenStale() ? null : delegate.getObject(key);
  }

  @Override
  public Object removeObject(Object key) { 
   
    clearWhenStale();
    return delegate.removeObject(key);
  }

  @Override
  public void clear() { 
   
    lastClear = System.currentTimeMillis();
    delegate.clear();
  }

  private boolean clearWhenStale() { 
   
	//当前时间-上次清除时间>缓存生效时间,如果大于则需要清空缓存
    if (System.currentTimeMillis() - lastClear > clearInterval) { 
   
      clear();
      return true;
    }
    return false;
  }
  • size —最大缓存引用对象
  • readWrite —是否可写,这里默认是true,需要缓存的数据实体需要实现Serializable接口,不然序列化会报错
  • blocking —是否阻塞

4.二级缓存获取调用链

org.apache.ibatis.cache.TransactionalCacheManager#getObject
org.apache.ibatis.cache.decorators.TransactionalCache#getObject
org.apache.ibatis.cache.decorators.SynchronizedCache#getObject
org.apache.ibatis.cache.decorators.LoggingCache#getObject
org.apache.ibatis.cache.decorators.SerializedCache#getObject
org.apache.ibatis.cache.decorators.ScheduledCache#getObject
org.apache.ibatis.cache.decorators.LruCache#getObject
org.apache.ibatis.cache.impl.PerpetualCache#getObject

5.二级缓存保存调用链

org.apache.ibatis.executor.CachingExecutor#close
org.apache.ibatis.cache.TransactionalCacheManager#commit
org.apache.ibatis.cache.decorators.TransactionalCache#flushPendingEntries
org.apache.ibatis.cache.decorators.SynchronizedCache#putObject
org.apache.ibatis.cache.decorators.LoggingCache#putObject
org.apache.ibatis.cache.decorators.SerializedCache#putObject
org.apache.ibatis.cache.decorators.ScheduledCache#putObject
org.apache.ibatis.cache.decorators.LruCache#putObject
org.apache.ibatis.cache.impl.PerpetualCache#putObject

6.如何清除二级缓存

同namespace下执行insert、update、delete方法会清除二级缓存

	@Test
    public void test1(){ 
   
        User user = userMappser.selectById(1);
        System.out.println(user);

        //进行更新,更新后二级缓存失效
        userMappser.updateById(1,"张三");

        User user1 = userMappser.selectById(1);
        System.out.println(user1);

        System.out.println(user == user1);
    }

结果集 中间增加更新语句导致二级缓存失效

在这里插入图片描述

6.两种配置需要注意的地方

先来看一个现象,我们现在采用@CacheNamespace配置,然后连续调用两个查询语句,中间增加一个xml中编写的update语句,代码如下

 	@Test
    public void test3(){ 
   
        User user = userMappser.selectById(1);
        System.out.println(user);

        //xml里写的update语句
        userMappser.updateByIdXml(1,"张三");
        //使用@update写的update语句
        //userMappser.updateById(1,"张三");

        User user1 = userMappser.selectById(1);
        System.out.println(user1);

        System.out.println(user == user1);
    }
	<update id="updateByIdXml">
        update user set username = #{username} where id = #{id}
    </update>

结果集
在这里插入图片描述

what the fuck?竟然还是命中了二级缓存


再来看一个例子,同样是@CacheNamespace,但是采用两个xml查询方法,看一下是否会用到二级缓存

 	@Test
    public void test2(){ 
   
        User user = userMappser.selectByIdXml(1);
        System.out.println(user);

        User user1 = userMappser.selectByIdXml(1);
        System.out.println(user1);

        System.out.println(user == user1);
    }

结果集 没有应用到二级缓存

在这里插入图片描述

这里我们看出来两种语句写法不能混用

这里需要强调的是,虽然@CacheNamespace和xml配置的方法二选其一,但是他们之间是不能相互支持的,注解方式只能支持@Select、@Update等注解方式方法,而xml只能支持写在xml文件中的select、update等语句,如果两种语句都用的话可能会导致二级缓存无法正常使用,切记!


以上为个人见解,如果表述有误或有所遗漏欢迎大家评论指出,共同学习,共同进步。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/191334.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • STM32单片机介绍_单片机智能控制DIY

    STM32单片机介绍_单片机智能控制DIYSTM32库函数开发系列文章目录第一篇:STM32F103ZET6单片机双串口互发程序设计与实现第二篇:最简单DIY基于STM32单片机的蓝牙智能小车设计方案第三篇:最简单DIY基于STM32F407探索者开发板的MPU6050陀螺仪姿态控制舵机程序第四篇:最简单DIY基于STM32F407探索者开发板和PCA9685舵机控制模块的红外遥控机械臂控制程序第五篇:注释最详细、代码最简单的STM32+摄像头+显示屏的颜色跟踪电路软硬件方案第六篇:最简单DIY基于STM32单片机的WIFI智能小车设计

    2022年10月17日
    0
  • npm安装yarn找不到命令行识别不了yarn安装的全局包问题「建议收藏」

    npm安装yarn找不到命令行识别不了yarn安装的全局包问题「建议收藏」这里写自定义目录标题npm安装yarn找不到命令行识别不了yarn安装的全局包问题npm安装yarn找不到命令行识别不了yarn安装的全局包问题npminstall-gyarnyarnglobaladd@vue/cli安装完之后命令行输入vue-V识别不了解决办法:在系统变量Path,添加你本地的yarn全局安装的包的路径…

    2022年10月21日
    0
  • 如何自定义类加载器_网易js加载器下载地址

    如何自定义类加载器_网易js加载器下载地址1.什么情况下需要自定义类加载器?(1)隔离加载类:在某些框架内进行中间件与应用的模块隔离,把类加载到不同的环境。比如,某容器框架通过自定义类加载器确保应用中依赖的jar包不会影响到中间件运行时使用的jar包。(jar包之间的冲突的消除)(2)修改类加载方式:类的加载模型并非强制,除Bootstrap外,其它的加载并非一定要引入,或者根据实际情况在某个时间点进行按需动态加载。(3)扩展…

    2022年9月5日
    2
  • flowable 集成mongodb

    flowable 集成mongodb学无止境,活到老学到老,每天都问自己进步了吗?1.背景由于公司每天有至少1500个表单发起,处理待办任务至少7000个,累计历史任务数据已经达到200多w条,时间一长,通过数据库查询已办的任何和我发起的流程巨慢所以我们考虑到这些数据能不能放入ES或者是mongodb中流程中心1.0版本集成的是ES,速度确实非常快,提升查询性能近万倍,但是由于ES是一个全文检索的系统,对我们这些业务数据来说…

    2022年5月18日
    102
  • Js 数组转JSON格式

    Js 数组转JSON格式要点1:转化函数 JSON.stringify()要点2:在js里写数组的时候是vardata=newArray()但是你如果是要转json显示的时候就要写成vardata={},不然转出来的json全是空的。先看一种错误格式:&lt;script&gt;    //定义一个数组    vardata=newArray();    for(vari=0;i…

    2022年6月21日
    50
  • hadoop集群启动步骤

    hadoop集群启动步骤hadoop集群启动步骤

    2022年4月23日
    57

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号