首页 > 其他分享 >mybatis一二级缓存简介

mybatis一二级缓存简介

时间:2024-03-20 16:37:34浏览次数:22  
标签:缓存 简介 SqlSession 查询 二级缓存 步骤 mybatis

一、前言

1,代码和准备工作见:mybatis工作原理简介 - seeAll - 博客园 (cnblogs.com)

 

二、一级缓存

1,效果展示

1.1,测试代码

代码中,使用SqlSession查询过一次数据;本例在此之后,继续添加一段代码,使用同样的SqlSession再次查询,观察结果数据来自于缓存还是数据库。

 

1.2,观察第一次查询的情况

如下图所示,第一次查询时,缓存为空,从而转向数据库查询数据。同时可知,缓存使用HashMap保存。

 

 

1.3,观察第二次查询的情况

如下图所示,第二次查询时,则直接使用了缓存中的数据库,没有再从数据库中查询了。

 

 

2,作用域

一级缓存的作用域只在SqlSession对象中。

 

2.1,测试代码

当前代码中,使用同一个SqlSession对象查询过两次数据,本例将第二次查询的代码做以下修改,即在第二次查询前将SqlSession对象指向一个新对象。准备执行如下操作:

a,执行第一次查询;

b,修改数据库数据;

c,执行第二次查询;

如果查询结果相同,则说明一级缓存的作用域不止限于SqlSession对象;反之,查询结果不相同,则说明一级缓存的作用域只限于SqlSession对象。

 

2.2,观察第一次查询的情况

和1.2中一样。

 

2.3,修改数据库中数据

 

2.4,观察第二次查询的情况

 

2.5,结果分析

根据以上测试结果,使用SqlSession对象查询数据后,再次使用另外一个SqlSession对象查询相同的数据,并没有从缓存中获取数据,而是从数据库重新查询了数据。可见,一级缓存的作用域仅限于SqlSession对象。

 

2.6,拓展

由以上认知,可以推测,如果一级缓存开启,那么在分布式环境中将会发生如下问题:

a,服务器A查询数据data1后,缓存了数据data1;

b,服务器B修改数据data1为data2;

c,服务器A使用同一个SqlSession对象查询数据,得到的结果为缓存的数据data1,而非当前最新数据data2。

解决办法:

2.6.1,mybatis配置文件设置localCacheScope

在mybatis配置文件中,设置localCacheScope=STATEMENT后,SqlSession每次查询后都会清除缓存。

        <setting name="localCacheScope" value="STATEMENT"/>

测试流程:

a,执行第一次查询;

b,修改数据库数据;

c,执行第二次查询;

结果,两次的查询结果是一样的,不符合预期。

原因:

a,debug了代码,第二次查询时,缓存中确实没有数据,也确实是从数据库查询的;

b,检查了mysql的缓存,只有一个have_query_cache参数,值是no,表示没有缓存;

c,修改数据库数据时,也带上了commit命令,第二次查询的结果还不是修改后的,而是原来的;

d,上网搜索jdbc connection相关问题,偶然发现说mybatis有个参数叫“自动提交”,设置成true和false是有区别的,我设置成true后问题解决。

类似于在sqlyog上按步执行以下步骤:

步骤1:START TRANSACTION;
步骤2:SELECT * FROM u_user;
步骤3:SELECT * FROM u_user;
步骤4:COMMIT;

在步骤2和步骤3之间插入一个操作,使用cmd链接mysql并修改数据库的数据,发现执行步骤3后查到的数据还是老数据。

如果在sqlyog上按步执行以下步骤:

步骤1:START TRANSACTION;
步骤2:SELECT * FROM u_user;
步骤3:COMMIT;
步骤4:START TRANSACTION;
步骤5:SELECT * FROM u_user;
步骤6:COMMIT;

在步骤2后执行操作,使用cmd链接mysql并修改数据库的数据,发现执行步骤5后查到的数据是修改后的数据。

总结下来,当前事务如果执行了查询操作并获得了查询结果,之后再执行相同的查询操作,便无法读取到其他事务已经提交的数据了。如果在步骤1后,让别的事务修改数据,执行步骤2能够读到其他事务提交的数据。

网上看了下,本例的情况属于“可重复读”,即一个事务里(事务开始,还没结束)每次读到的值都是一样的,不管中间其他事务是否修改。也有的时候是“不可重复读”,即一个事务里每次都能读到其他事务已经提交的数据。

-- 设置为:不可重复读
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 设置为:可重复读。(按本例,mysql默认可重复读)
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

2.6.2,mybatis的一级缓存配置为redis

通过一定的方式(可网上查看),程序员可以让mybatis的一级缓存由原先的HashMap修改为redis,HashMap是服务器jvm私有的,redis是所有服务器共有的。

2.6.3,关闭mybatis缓存,使用redis

和2.6.2不同的是,由程序员来完成缓存的动作,而不是交给mybatis去缓存。比如使用spring-cache,在有些查询方法上面加上@Cacheable,下回查询时就会使用缓存。

 

三、二级缓存

和一级缓存默认开启不同,二级缓存需要手动开启。

 

1,开启二级缓存

1.1,mybatis配置文件修改

在mybatis配置文件中添加如下配置

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

 

1.2,mapper映射文件修改

在mapper.xml映射文件中添加如下配置

    <!-- 使用默认配置,实体对象需要序列化 -->
    <cache></cache>

 

1.3,实体类修改

实体类需要序列化,默认配置时,缓存对象时序列化了;获取缓存时,会反序列化

 

1.4,测试代码修改

a,使用两个不同的SqlSession对象进行查询,从而排除一级缓存的情况,以测试二级缓存。根据上面对一级缓存的测试可知,使用两个不同的SqlSession对象是不走一级缓存的。

b,SqlSession执行查询后需要关闭,否则二级缓存不生效?即使设置“自动提交”为true也无法使二级缓存生效。效果是当SqlSession关闭,“自动提交”不管为true还是false时,二级缓存都能生效。

 

2,效果展示

2.1,观察第一次查询的情况

 

2.2,观察第二次查询的情况

 

3,作用域

3.1,第一次查询

如下图,CacheExecutor中的缓存编号1256,LruCache中的缓存编号1261。

 

 

3.2,第二次查询

如下图,CacheExecutor中的缓存编号1723,LruCache中的缓存编号1261。

 

3.3,总结

  CacheExecutor LruCache
第一次查询 1256 1261
第二次查询 1723 1261

查询时,虽然使用了不同的对象来操作缓存数据,但是数据都是保存到同一个缓存对象(LruCache)中的。

当使用不同的SqlSessionFactory对象时,缓存对象会不一样。

 

 

四、总结

1,一级缓存在同一个SqlSession对象中是有效的;

2,二级缓存在同一个SqlSessionFactory对象中是有效的;

3,一二级缓存都可以指向如redis一样的容器,以应对分布式的情况;

4,一级缓存默认开启,也可以通过配置达到“关闭”的效果;二级缓存默认关闭,需要在多个地方进行配置,以使其生效;

5,mybatis有许多默认配置,如“自动提交”默认为false;二级缓存的默认配置,如清除策略,本例为LRU,还可以配置成FIFO等,如序列化,有些配置下不需要序列化,本例缓存对象序列化取出对象反序列化;

6,分析mybatis的行为时,需要考虑数据库本身的配置;比如本例中,mybatis关闭了一级缓存,前后两次查询之间其他事务执行了更新操作,最终的查询结果仍然一样,让人误以为一级缓存没有真正关闭或者误以为mybatis有隐藏动作,实际是因为数据库设置了事务的隔离级别为“可重复读”,导致一个事务中多次查询结果重复。

标签:缓存,简介,SqlSession,查询,二级缓存,步骤,mybatis
From: https://www.cnblogs.com/seeall/p/18084634

相关文章

  • Spring中@NotNull注解@Valid注解简介及使用
    前言在开发中,为了代码的稳定性不报空指针异常,经常需要判断前端传过来的值是否为空,为空的话就返回前端值为空的提示,才能进行下一步的操作,例如登录操作需要判断传过来的登录名和密码是否为空:@GetMapping("login")publicResultlogin(Useruser){if(StringUti......
  • 盒子模型简介
    在CSS中,盒子模型描述了一个元素所占用的空间,包括内容(content)、内边距(padding)、边框(border)和外边距(margin)几个部分。内边距(padding)和外边距(margin)都是盒子模型的一部分,但它们的作用和表现有所不同。内边距(Padding)内边距是指内容(如文本、图片等)与边框之间的空间。它位于元素的边......
  • Mybatis设置默认值
    在MyBatis中,可以通过在<resultMap>中使用<result>标签的column属性来设置默认值。但是,MyBatis本身不直接支持在<select>查询中设置默认值。如果需要为查询结果中的某个字段设置默认值,可以在结果映射中处理,或者在应用层面进行处理。以下是一个使用<resultMap>设置默认值的例......
  • SpringBoot整合Mybatis-Plus(SpringBoot3)
    依赖pom.xml:pom.xml<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://......
  • NXP ECSPI controller简介
    spi协议可参考:https://www.cnblogs.com/lethe1203/p/18083528 ECSPI(EnhancedConfigurableSerialPeripheralInterface)是由NXPSemiconductors(原飞利浦半导体部门)开发的,imx6ull上一共有四组spi接口,每组寄存器都是一样的,都是以第一组为例。 典型的SPIBURST传输图: ECSP......
  • MyBatis3源码深度解析(十六)SqlSession的创建与执行(三)Mapper方法的调用过程
    文章目录前言5.9Mapper方法的调用过程5.10小结前言上一节【MyBatis3源码深度解析(十五)SqlSession的创建与执行(二)Mapper接口和XML配置文件的注册与获取】已经知道,调用SqlSession对象的getMapper(Class)方法,传入指定的Mapper接口对应的Class对象,即可获得一个动态......
  • 基于SSM框架的商城的设计与实现(JSP+java+springmvc+mysql+MyBatis)
    本项目包含程序+源码+数据库+LW+调试部署环境,文末可获取一份本项目的java源码和数据库参考。项目文件图 项目介绍随着电子商务的迅猛发展,网上购物已成为人们日常生活的一部分。基于SSM(Spring+SpringMVC+MyBatis)框架的商城系统因其轻量化、高效和易于维护等特点,成为......
  • 在线选课系统(JSP+java+springmvc+mysql+MyBatis)
    本项目包含程序+源码+数据库+LW+调试部署环境,文末可获取一份本项目的java源码和数据库参考。项目文件图 项目介绍在线选课系统作为现代教育体系中重要的信息化工具,它允许学生通过互联网进行课程选择,提高了教育管理的灵活性和效率。随着教学模式的多样化和个性化学习需求......
  • 基于携程旅行平台自由行的旅游线路管理信息系统(JSP+java+springmvc+mysql+MyBatis)
    本项目包含程序+源码+数据库+LW+调试部署环境,文末可获取一份本项目的java源码和数据库参考。项目文件图项目介绍随着个性化旅游需求的增加,自由行成为越来越多旅行者的选择。基于携程旅行平台的自由行旅游线路管理信息系统,旨在为用户提供更加灵活、个性化的旅游规划服务。系......
  • 二手车市场商户管理系统(JSP+java+springmvc+mysql+MyBatis)
    本项目包含程序+源码+数据库+LW+调试部署环境,文末可获取一份本项目的java源码和数据库参考。项目文件图项目介绍随着汽车消费市场的成熟和车辆更新换代的加快,二手车交易日益频繁,形成了庞大的二手车市场。针对市场中商户的管理而言,存在着信息杂乱、交易不透明、监管困难等问......