首页 > 其他分享 >mybatis06_mybatis缓存

mybatis06_mybatis缓存

时间:2023-03-23 15:56:35浏览次数:48  
标签:缓存 MyBatis 二级缓存 mybatis SqlSession mybatis06 sqlSession 加载

MyBatis缓存的概念

​ 它用来优化 SQL 数据库查询的,但是可能会产生脏数据。

​ 一级缓存是存在于 SqlSession 中的,而 SqlSession 就是操作数据库的一个会话对象。在 SqlSession 对象中实际使用了一个 HashMap 的数据结构用于存储缓存数据,不同的 SqlSession 之间的缓存数据互不影响。

​ 二级缓存是 mapper 级别的缓存,当多个 SqlSession 操作同一个 mapper.xml 配置中的 SQL 语句时,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession的。

image-20230323090215692

一、一级缓存

​ Mybatis默认开启。一级缓存的作用域在同一个 SqlSession 中,若同一个 SqlSession 执行两次相同的 Sql 语句,第一次执行完毕后会将数据放入缓存,第二次直接在缓存中取。当SqlSession结束,其中的缓存也消失。

image-20230323090532743

​ 我们随便找一个例子测试

​ 在这个案例中我们再写一个 findById 来测试一下,比较简单,这里就只给关键部分和结果解析。

    private static void testOneLeverCache() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
            Emp emp = empMapper.findByID(11L);
            System.out.println(emp);
            //在这儿开启事务提交
//            sqlSession.commit();
            System.out.println("__________");
            Emp emp2 = empMapper.findByID(11L);
            System.out.println(emp);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {sqlSession.close();}
        }
    }

⬇️执行了一次 sql 语句的 preparing

image-20230323092543287

​ 如果 SqlSession 执行 insert、update、delete 等操作 commit 提交后会清空一级缓存,这样做的目的是为了让缓存中存储的数据是最新的信息,避免脏读。

⬇️提交事务,一级缓存内容消失

image-20230323092828155

二、二级缓存

​ 在 MyBatis 中允许多个 SqlSession 对象共享一个缓存区域,这个缓存区域并一定在内存中,也可能是存储硬盘空间内,这个共享区域就是 MyBatis 的二级缓存。同样使用 HashMap 这种数据结构来存储二级缓 存中保存的数据。

image-20230323094132093

​ MyBatis 默认关闭二级缓存,需要在配置中手动开启

​ ①在 mybatis-config.xml 中设置二级缓存开启

<!--开启二级缓存-->
    <settings>
        <setting name="CacheEnabled" value="true"/>
    </settings>

​ ②在 mapper 文件中加入 cache 标签

<mapper namespace="com.ls.mapper.EmpMapper">
    <cache/>
</mapper>

​ 二级缓存的查询结果对应的 POJO 对象需要实现 Serializable 接口(如果存在父类、以及成员 pojo 都需要实现序列化接口)。下面是测试案例。

⬇️一定要实现序列化接口

image-20230323095424815

⬇️下面是测试代码,还是用上面那个

​ 为测试二级缓存,使用 close 关闭当前的 SqlSession 以绕过一级缓存,获取另一个 SqlSession 后执行相同的 sql 语句。

private static void testTwoLeverCache() {
        SqlSession sqlSession = null;
        SqlSession sqlSession2 = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
            Emp emp = empMapper.findByID(11L);
            System.out.println(emp);
            System.out.println("_____________________");
            sqlSession.close();
            //关闭sqlsession以清除一级缓存
            sqlSession2 = MybatisUtil.getSqlSession();
            EmpMapper empMapper2 = sqlSession2.getMapper(EmpMapper.class);
            Emp emp2 = empMapper2.findByID(11L);
            System.out.println(emp2);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {sqlSession.close();}
        }
    }

​ 注意不要使用已经关闭的 SqlSession,不然就会像下面这样。可以看一下这里的文章

​ PS:当让你可以直接sqlSession.commit() 来清空缓存,也能将一缓存到二缓,这是后来知道的。。。。。。

 Cause: org.apache.ibatis.executor.ExecutorException: Executor was closed.

⬇️结果

​ 缓存命中率为 0.5

image-20230323101154821

三、缓存查询的先后顺序

​ 首推这位大佬的文章,想测试的大佬都测了。

​ 当一级缓存和二级缓存都支持时,MyBatis 会先从二级缓存中查询(别的 SqlSession 可能之前将所需要的数据存到了二级缓存中);如果二级缓存没有命中才会查询一级缓存,最后在去数据库中查询;当 sqlSession 关闭或者事务提交时,一级缓存的数据会写入二级缓存。

四、MyBatis二级缓存整合Ehcache

因为用不到所以简写了

​ MyBatis 的特长是 SQL 操作,而不是缓存管理,为了提高缓存的性能将 MyBatis 框架与第三方的缓存数据库框架整合即可,如 ehcache、redis、memcache 等。

​ ①引入依赖包

<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>

​ ②添加配置文件 ehcache.xml

<?xml version="1.0" encoding="UTF-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNameSpaceSchemaLocation="./ehcache.xsd">
<!--
path 属性指定缓存数据的存储路径,属性值可以指定一个盘符目录
例如:D:/temp 或者 java.io.temdir,这个值表示系统的缓存路径
为:C:/users/administrator/AppData/local/Temp
-->
<diskStore path="java.io.temdir"/>
<defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="120"
maxElementsOnDisk="10000" diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU" />
</ehcache>

​ ③在mapper中指向ehcache

<cache type="org.mybatis.caches.ehcache.EhcacheCache" />

五、Mybatis延迟加载

https://www.cnblogs.com/purearc/p/17216578.html动态sql

1、延迟加载的概念

​ 延迟加载就是先查询主表的信息,主表信息查询完成后当需要的时候再按照主表相关数据完成关联信息的查询,即在 sql 查询中先查询一部分(主表信息),再查询另一部分(关联表信息)。

2、配置开启延迟加载

⬇️在配置文件中开启延迟加载

​ lazyLoadingEnabled:全局性设置懒加载。如果设为‘false’,则所有相关联属性都会被初始化加载。

​ aggressiveLazyLoading:当设置为‘true’的时候,懒加载的对象的任何懒属性会被全部加载。设置为 false 时,每个属性都按需加载

<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>

​ 真是长见识了,才知道 dtd 校验里面有节点的先后顺序。

image-20230323150933289

3、实现

​ 因为实现延迟加载和前面的 association 和 collection有关,所以用一对多关系那个模块的代码测试。

⬇️在mapper.xml 文件中配置

association 中的 select 值为要嵌套的 sql 子句,column 的值为 “要把主表的哪个列的值代入子 sql 语句” ,在这里我们把主表 id_card 中的属性列 person_id 代入了 elect id,person_name personName from person where id = ? 中。

<!--延迟加载-->
    <select id="list3" resultMap="IdCardMap2">
        select id_card.* from id_card
    </select>

    <resultMap id="IdCardMap2" type="com.ls.pojo.IdCardExtends">
        <id property="id" column="id"></id>
        <result property="cardNum" column="card_num"></result>
        <association property="person" javaType="com.ls.pojo.Person" select="queryPersonById" column="person_id">
        </association>
    </resultMap>
    <select id="queryPersonById" resultType="com.ls.pojo.Person">
        select id,person_name personName from person where id = #{personId}
    </select>

⬇️测试部分

​ 通过 MyBatis 实现延迟加载,其本质就是执行 SQL 查询时,如果调用 Mapper 接口中的 list3 方法 时,只会执行该接口对应的 SQL 语句,并返回一个 idCardExtends 对象。resultMap 中包含的 queryPersonById 对应的 SQL 并不会执行,只有当调用 idCardExtends 对象的 getPerson 方法时,MyBatis 才会去执行 queryPersonById 对应的 SQL。

 private static void testLazyLoad() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
            IdCardMapper idCardMapper = sqlSession.getMapper(IdCardMapper.class);
            List<IdCardExtends> personList =  idCardMapper.list3();
            for (IdCardExtends idCardExtends : personList) {
                System.out.println(idCardExtends.getCardNum());
//                System.out.println(idCardExtends.getCardNum()+":"+idCardExtends.getPerson());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {sqlSession.close();}
        }
    }

⬇️不调用getPerson

image-20230323153232751

⬇️调用getPerson

image-20230323153138706

六、下载

​ Mybatis 基础的部分暂时这些,之后的 Mybatis 源码的简单理解和 MybatisPlus、整合 Redis 、面试题等的理解会再开一部分。

​ 整个工程下载地址:click here

标签:缓存,MyBatis,二级缓存,mybatis,SqlSession,mybatis06,sqlSession,加载
From: https://www.cnblogs.com/purearc/p/17247736.html

相关文章

  • Mybatis配置映射文件中parameterType的用法小结
    原创:在mybatis映射接口的配置中,有select,insert,update,delete等元素都提到了parameterType的用法,parameterType为输入参数,在配置的时候,配置相应的输入参数类型即可。param......
  • SpringBoot中如何解决Redis的缓存穿透、缓存击穿、缓存雪崩?
    本文正在参加「金石计划」大家好,我是飘渺!今天给大家介绍一下如何在SpringBoot中解决Redis的缓存穿透、缓存击穿、缓存雪崩的问题。缓存穿透什么是缓存穿透缓存穿透指的......
  • Solr 缓存配置
    Solr缓存与Solr的索引搜索器(SolrIndexSearcher)息息相关的,而众所周知,索引的结构很难做出大的变动,效率也是板上钉钉的事情。因此提高索引搜索器的使用效率,使之在任何缓存都能......
  • MyBatis各个版本下载 以及 Apache Maven 安装
    推荐下面两篇文章:实测有效! MyBatis下载和环境搭建Maven详细安装教程 ......
  • Mybatis图解(转载)
    前言今天我们来从一个全局的角度看看Mybatis。Mybatis工作流程Mybatis工作流程可以大致分为四个步骤:下面我们就来说说这四个步骤:加载配置并初始化触发条件:加载配置......
  • MyBatis学习日志
    在pom.xml导入依赖<dependencies><!--导入mysql驱动jar包--><dependency><groupId>mysql</groupId><artifactId>mysql......
  • MybatisPlus学习笔记
    MybatisPlus初始化创建boot项目的时候导入mysql的依赖,创建好以后在里边导入MybatisPlus的坐标(这个坐标包含和mybatis的相关坐标和spring整合mybatis的相关坐标,所以自......
  • [MyBatis]mapperLocations属性通配符的使用
    示例:<beanid="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean"><propertyname="dataSource"ref="dataSource"/><propertyname="......
  • Mybatis-Flex 一个优雅的 Mybatis 增强框架
    Mybatis-Flex:更灵活、更轻量、更好用特征很轻量,整个框架只依赖Mybatis再无其他第三方依赖只增强,支持Entity的增删改查、及分页查询,但不丢失Mybatis原有功能内......
  • Mybatis
    目录Mybatis1、简介1.1、什么是Mybatis1.2、持久层1.4、为什么需要Mybatis?2、第一个Mybatis程序2.1、搭建环境2.2、创建一个模块2.4、测试3、CRUD1.namespace2、select3、I......