Mybatis一级缓存详解

目录

一级缓存

一级缓存的组织

一级缓存的生命周期

一级缓存的工作流程

Cache接口的设计以及CacheKey的定义

一级缓存的性能分析

一级缓存与Spring

事务一级缓存存在的弊端

官方文档分析

Spring通过Mybatis调用数据库的过程


  • 一级缓存

  • 对于会话(Session)级别的数据缓存,我们称之为一级数据缓存,简称一级缓存
  • Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言
  • SqlSession:应用程序和数据库之间交互的一个单线程对象(非线程安全的)不同用户连接的不是同一个
  • 由于Mybatis使用SqlSession对象表示一次数据库的会话,那么,对于会话级别的一级缓存也应该是在SqlSession中控制的
  • 在操作数据库时需要构造sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据
  • 不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的,也就是它只能作用在同一个sqlSession中,不同的sqlSession中的缓存是互相不能读取的
  • 一级缓存在操作数据库时需要构造sqlSession对象
  • 但和数据库操作有关的职责都会委托给Executor,通过BaseExecutor中的PerpetualCache localCache(底层就是一个Hashmap)
  • 作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空
  • 使用一级缓存,共有两个选项,SESSION或者STATEMENT
  • 默认是SESSION级别,即在一个Mybatis会话中执行的所有语句,都会共享这一个缓存
  • 一种是STATEMENT级别,可以理解为缓存只对当前执行的这一个Statement有效
  • 每个SqlSession中持有了Executor,每个Executor中有一个LocalCache(所以一级缓存是SqlSession级别的)
  • 当用户发起查询时,MyBatis根据当前执行的语句生成MappedStatement( 如: mapper.StudentMapper.getStudentById ),在Local Cache进行查询
  • 如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入Local Cache,最后返回结果给用户
  • 一级缓存的组织

  • 实际上,MyBatis只是一个MyBatis对外的接口
  • SqlSession将它的工作交给了Executor执行器这个角色来完成,负责完成对数据库的各种操作
  • 当创建了一个SqlSession对象时,MyBatis会为这个SqlSession对象创建一个新的Executor执行器,而缓存信息就被维护在这个Executor执行器中,MyBatis将缓存和对缓存相关的操作封装在Cache接口中
  • Executor接口的实现类BaseExecutor中拥有一个Cache接口的实现类PerpetualCache,则对于BaseExecutor对象而言,它将使用PerpetualCache对象维护缓存
  • 由于Session级别的一级缓存实际上就是使用PerpetualCache维护的,那么PerpetualCache是怎样实现的呢?
  • PerpetualCache实现原理其实很简单,其内部就是通过一个简单的HashMap<k,v> 来实现的,没有其他的任何限制
  • 一级缓存的生命周期

  • Mybatis在开启一个数据库会话时,会创建一个新的SqlSession对象,每个SqlSession对象中会有一个新的Executor执行器
  • Executor执行器中持有一个新的PerpetualCache对象
  • 当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉
  • 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用
  • 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用
  • SqlSession中执行了任何一个update操作(update()、delete()、insert()) 并执行commit操作,都会清空PerpetualCache对象的数据,但是该对象可以继续使用,目的是避免脏读,再次相同sql查询,会查询数据库,此时一级缓存失效
  • 一级缓存的工作流程

  • 1.对于某个查询,根据statementId,params,rowBounds来构建一个key值,根据这个key值去缓存Cache中取出对应的key值存储的缓存结果;
  • 2.判断从Cache中根据特定的key值取的数据是否为空,即是否命中;
  • 3.如果命中,则直接将缓存结果返回;
  • 4.如果没命中:
    • 4.1去数据库中查询数据,得到查询结果;
    • 4.2将key和查询到的结果分别作为key,value对存储到Cache中;
    • 4.3将查询结果返回;
  • 5.结束
  • Cache接口的设计以及CacheKey的定义

  • MyBatis定义了一个org.apache.ibatis.cache.Cache接口作为其Cache提供者的SPI(Service Provider Interface)
  • 所有的MyBatis内部的Cache缓存,都应该实现这一接口
  • MyBatis定义了一个PerpetualCache实现类实现了Cache接口,实际上,在SqlSession对象里的Executor对象内维护的Cache类型实例对象,就是PerpetualCache子类创建的(MyBatis内部还有很多Cache接口的实现,一级缓存只会涉及到这一个PerpetualCache子类,Cache的其他实现将会放到二级缓存中介绍)
  • Cache最核心的实现其实就是一个Map,将本次查询使用的特征值作为key,将查询结果作为value存储到Map中
  • 现在最核心的问题出现了:怎样来确定一次查询的特征值?
  • 换句话说就是:怎样判断某两次查询是完全相同的查询?
  • 也可以这样说:如何确定Cache中的key值?
  • MyBatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询:
    • 1.传入的 statementId
    • 2.查询时要求的结果集中的结果范围 (结果的范围通过rowBounds.offset和rowBounds.limit表示)
    • 3.这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql())
    • 4.传递给java.sql.Statement要设置的参数值
  • 现在分别解释上述四个条件:
    • 1.传入的statementId,对于MyBatis而言,你要使用它,必须需要一个statementId,它代表着你将执行什么样的Sql
    • 2.MyBatis自身提供的分页功能是通过RowBounds来实现的,它通过rowBounds.offset和rowBounds.limit来过滤查询出来的结果集,这种分页功能是基于查询结果的再过滤,而不是进行数据库的物理分页
    • 由于MyBatis底层还是依赖于JDBC实现的,那么,对于两次完全一模一样的查询,MyBatis要保证对于底层JDBC而言,也是完全一致的查询才行
    • 而对于JDBC而言,两次查询,只要传入给JDBC的SQL语句完全一致,传入的参数也完全一致,就认为两次查询是完全一致的
    • 上述的第3个条件正是要求保证传递给JDBC的SQL语句完全一致
    • 第4条则是保证传递给JDBC的参数也完全一致
  • 综上所述,CacheKey由以下条件决定:
    • statementId + rowBounds + 传递给JDBC的SQL + 传递给JDBC的参数值
  • CacheKey的创建

  • 对于每次的查询请求,Executor都会根据传递的参数信息以及动态生成的SQL语句,将上面的条件根据一定的计算规则,创建一个对应的CacheKey对象
  • 我们知道创建CacheKey的目的,就两个:
    • 1.根据CacheKey作为key,去Cache缓存中查找缓存结果
    • 2.如果查找缓存命中失败,则通过此CacheKey作为key,将从数据库查询到的结果作为value,组成key,value对存储到Cache缓存中
  • CacheKey的构建被放置到了Executor接口的实现类BaseExecutor中
  • 刚才已经提到,Cache接口的实现,本质上是使用的HashMap,而构建CacheKey的目的就是为了作为HashMap中的key值
  • 而HashMap是通过key值的hashCode来组织和存储的,那么,构建CacheKey的过程实际上就是构造其hashCode的过程
  • 一级缓存的性能分析

  • MyBatis对会话(Session)级别的一级缓存设计的比较简单,就简单地使用了HashMap来维护,并没有对HashMap的容量和大小进行限制
  • 如果一直使用某一个SqlSession对象查询数据,这样会不会导致HashMap太大,而导致 java.lang.OutOfMemoryError错误啊?不过MyBatis的确是这样设计的
  • MyBatis这样设计也有它自己的理由:
  • (1)一般而言SqlSession的生存时间很短;一般情况下使用一个SqlSession对象执行的操作不会太多,执行完就会消亡
  • (2)对于某一个SqlSession对象而言,只要执行update操作(update、insert、delete),都会将这个SqlSession对象中对应的一级缓存清空掉,所以一般情况下不会出现缓存过大,影响JVM内存空间的问题
  • (3)可以手动地释放掉SqlSession对象中的缓存
  • 一级缓存是一个粗粒度的缓存,没有更新缓存和缓存过期的概念:
  • MyBatis的一级缓存就是使用了简单的HashMap,MyBatis只负责将查询数据库的结果存储到缓存中去,不会去判断缓存存放的时间是否过长、是否过期,因此也就没有对缓存的结果进行更新这一说了
  • 根据一级缓存的特性,在使用的过程中应该注意:
  • (1)对于数据变化频率很大,并且需要高时效准确性的数据要求,使用SqlSession查询的时候,要控制好SqlSession的生存时间,SqlSession的生存时间越长,它其中缓存的数据有可能就越旧,从而造成和真实数据库的误差;同时对于这种情况,用户也可以手动地适时清空SqlSession中的缓存
  • (2)对于只执行、并且频繁执行大范围的select操作的SqlSession对象,SqlSession对象的生存时间不应过长
  • 一级缓存与Spring

  • 实际开发中,Mybatis通常和Spring进行整合开发
  • Spring将事务放到Service中管理,对于每一个service中的sqlsession是不同的,这是通过mybatis-spring中的org.mybatis.spring.mapper.MapperScannerConfigurer创建sqlsession自动注入到service中的
  • 每次查询之后都要进行关闭sqlSession(每次查询也会新建sqlsession),关闭之后数据被清空
  • 所以Spring整合之后,如果没有事务,一级缓存是没有意义的
  • 总的来说,Spring结合Mybatis后,Mybatis一级缓存分为两种情况:
  • 如果没有开启事务,每一次sql都是用的新的SqlSession,这时mybatis的一级缓存是失效的
  • 如果有事务,同一个事务中相同的查询使用的相同的SqlSession,此时一级缓存是生效的
  • 判断是否是同一个SqlSession可以把日志级别降到debug级别查看相应的SqlSessionId是否为多个
  • 事务一级缓存存在的弊端

  • 同一个事务中在查询中间如果有其他线程修改了这条数据,这两条两次查询的内容还是相同(事务使用的是Read Committed)
  • 因为同一个事务中Spring使用的是同一个SqlSession,此时走的是SqlSession的缓存,并没有从数据中查询
  • 解决方案:
  • 在Mybatis的mapper.xml里配置清空缓存flushCache设置为true

  • 官方文档分析

  • (1)Using an SqlSession
  • 在MyBatis中,使用sqlsessionFactory创建一个sqlsession
  • 一旦有了会话,就可以使用它来执行Mapper的映射语句、提交或回滚连接,最后,当不再需要时,关闭会话
  • 使用mybatis-spring,您不需要直接使用sqlsessionFactory,因为可以向bean注入一个线程安全的sqlsession,它根据spring的事务配置自动提交、回滚和关闭会话
  • (2)SqlSessionTemplate
  • SqlSessionTemplate 是mybatis-spring 的心脏
  • 它实现了sqlsession,是为了作为代码中任何现有使用sqlsession的替代品
  • sqlsessionTemplate是线程安全的,可以由多个DAO或映射器共享
  • 当调用SQL方法(包括getmapper()返回的映射器中的任何方法)时,sqlsessionTemplate将确保使用的sqlsession是与当前spring事务关联的
  • 此外,它还管理会话生命周期,包括根据需要关闭、提交或回滚会话
  • 它还将mybatis异常转换为spring DataAccessExceptions
  • 应始终使用sqlsessiontemplate而不是默认的mybatis实现默认的sqlsession
  • 因为模板可以参与Spring事务,并且对于多个注入的映射器类来说是线程安全的
  • 在同一应用程序中的两个类之间切换可能会导致数据完整性问题
  • Spring通过Mybatis调用数据库的过程

  • 1、需要访问数据
  • 2、spring检查到了这种需求,于是去申请一个mybatis的sqlsession,并将申请到的sqlsession与当前线程绑定,放入threadlocal里面
  • 3、template从threadlocal获取到sqlsession,去执行查询
  • 4、查询结束,清空threadlocal中与当前线程绑定的sqlsession,释放资源
  • 5、又需要访问数据
  • 6、返回到步骤2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/19271.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

chanmama响应数据解析

0x00目标url aHR0cHM6Ly93d3cuY2hhbm1hbWEuY29tL2F1dGhvckRldGFpbC85OTI0MjExODcxOC9wcm9tb3Rpb24 0x01接口分析 简单的get 但是返回数据被加密了 这里我们就来想想怎么解密这些数据。首先后端发来的数据是加密的&#xff0c;但是我们在前端看到的可不是加密后的数据。前端…

什么是零拷贝?

零拷贝 什么是零拷贝 零拷贝指的是&#xff0c;从一个存储区域到另一个存储区域的copy任务无需CPU参与就可完成。零拷贝的底层是 通过DMA总线技术实现的。零拷贝与具体的编程语言无关&#xff0c;完全依赖于OS&#xff0c;OS支持就可使用&#xff0c;不支持 设置了也不起作用…

大厂视频面试,因为截屏作废

大厂视频面试现在这么严格了么&#xff1f;无意间按到截屏直接显示面试作废&#xff0c;好在最后和HR解释了下&#xff0c;再约时间重新面。 作为一个面试过3、4家大厂&#xff0c;现在在鹅厂工作的过来人来说&#xff0c;上面遇到的这个问题是AI面&#xff0c;不用太担心&…

笔记本电脑开机黑屏没反应怎么办?

笔记本电脑开机黑屏没反应怎么办&#xff1f;有用户电脑开机之后&#xff0c;桌面会变成黑屏显示。而且是常常都会出现这样的问题&#xff0c;非常影响自己的电脑使用体验。那么遇到这个问题要怎么去进行问题的解决呢&#xff1f;来看看以下的解决方法吧。 准备工作&#xff1a…

玩游戏时突然弹出”显示器驱动程序已停止响应并且已恢复”怎么办

随着3A游戏大作不断面市&#xff0c;用户也不断地提升着自己的硬件设备。但是硬件更上了&#xff0c;却还会出现一些突如其来的情况&#xff0c;比如正准备开启某款游戏时&#xff0c;电脑右下角突然出现“显示器驱动程序已停止响应并且已恢复”。遇事不慌&#xff0c;驱动人生…

java lambda表达式详解

一、Lambda初识 我们知道&#xff0c;在Java中&#xff0c;接口是不能实例化的&#xff0c;但是接口对象可以指向它的实现类对象。如果接口连实现对象都没有呢&#xff1f;那还可以使用匿名类的方式&#xff0c;如下: public class JavaTest { public static void main(Strin…

某程序员哀叹:二本计算机,4年开发,年包才40多万。二本真的不如985/211吗?

前段时间&#xff0c;某职场论坛上有人发了一个帖子&#xff0c;发帖人问&#xff1a;为什么大家工资那么高&#xff0c;三五年都六七十万了&#xff1f;我二本计算机专业&#xff0c;四年前端开发&#xff0c;找个年包40万多点就顶头了。 原贴如下&#xff1a; 有网友表示楼主…

2022年平均工资出炉,IT行业又是第一

根据5月9日国家统计局最新资料显示&#xff0c;2022年&#xff0c;全国城镇非私营单位就业人员年平均工资为114029元&#xff0c;比上年增长6.7%&#xff0c;扣除通胀后实际增长4.6%。其中&#xff0c;行业间的差距相当明显。根据资料显示&#xff0c;2022年无论是在私营单位还…

Android---bitmap优化

目录 Bitmap 占用内存大小计算 Bitmap | Drawable | InputStream | Byte[] 之间进行转换 Bitmap 相关方法 BitmapFactory 工厂类 Bitmap 占用内存大小计算 Bitmap 作为位图&#xff0c;需要读入一张图片中每一个像素点的数据&#xff0c;其主要占用内存的地方也正是这些像…

python进阶--月考二

python进阶--月考二 &#xff08;一&#xff09;装饰器&#xff08;二&#xff09;创建名为express.py文件&#xff0c;编写以下推导式&#xff08;25分&#xff09;&#xff08;三&#xff09;创建名为process_test.py的文件&#xff0c;计算1-3000之间的水仙花数&#xff08;…

QT MD4 MD5 Sha1等几种加密方式

QT MD4 MD5 Sha1等几种加密方式 [1] QT MD4 MD5 Sha1等几种加密方式[2] qt MD5 和AES 加密一 、MD5 加密二、AES 加密和解密 [3] QT中sqlite数据库数据加密/混淆---MD5/SHA1/SHA2/SHA3&#xff08;1&#xff09;创建一个加密对象&#xff08;2&#xff09;放入要加密的数据&…

目前可用的ChatGPT网站

本文意在整理可用gpt-3.5、gpt-4.0等网站。 本文主要是方便自己翻阅&#xff0c;如对您也有所帮助&#xff0c;不胜荣幸~ 文章目录 chatgpt.qdymys.cngpttalkchatgpt-cn.cobing.comchat机器人wuguokai.cn总结 chatgpt.qdymys.cn 网址&#xff1a;https://chatgpt.qdymys.cn/限…

SpringCloud —— eureka

目录 1.认识微服务 1.0.学习目标 1.1.单体架构 1.2.分布式架构 1.3.微服务 1.4.SpringCloud 1.5.总结 2.服务拆分和远程调用 2.1.服务拆分原则 2.2.服务拆分示例 2.2.1.导入Sql语句 2.2.2.导入demo工程 2.3.实现远程调用案例 2.3.1.案例需求&#xff1a; 2.3.2.注…

mysql进阶-查询优化-慢查询日志

文章目录 一、什么是慢查询日志二、慢查询日志能干什么2.1 性能分析和优化2.2 诊断和排查问题2.3 数据分析和探索 三、慢查询日志实战3.1 永久开启开启慢查询日志3.2 临时开启慢查询日志3.4 常用命令 四、如何分析慢查询日志五、优化慢查询语句五、总结 一、什么是慢查询日志 …

观察者设计模式(Observer Design Pattern)[论点:概念、组成角色、相关图示、示例代码、框架中的运用、适用场景]

文章目录 概念组成角色相关图示示例代码框架中的运用适用场景 概念 观察者设计模式&#xff08;Observer Design Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一种对象间的一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象&#xff0c;当…

SpringBoot 配置文件

前言&#xff1a; 本篇主要介绍两种配置文件格式&#xff0c;分别为properties与yml(yaml)。 需要注意的是&#xff1a; 两个配置文件从功能上来讲是可以同时存在的&#xff0c;但是企业中通常会规定使用某一种格式的配置文件。如果同一个配置出现在两种格式的配置文件中的话&a…

微波方向有哪些SCI期刊推荐? - 易智编译EaseEditing

微波方向的SCI期刊推荐包括&#xff1a; IEEE Transactions on Microwave Theory and Technology&#xff1a; 该期刊是电磁场与微波技术领域的著名期刊&#xff0c;被世界上许多研究机构和大学广泛引用。 IEEE Transactions on Antennas and Propagation&#xff1a; 该期刊…

English Learning - L3 作业打卡 Lesson1 Day5 2023.5.9 周二

English Learning - L3 作业打卡 Lesson1 Day5 2023.5.9 周二 引言&#x1f349;句1: Fast loud music is popular with many people .成分划分爆破语调 &#x1f349;句2: They may say the music is red hot, especially the kind called Dixieland jazz.成分划分爆破语调 &a…

AI孙燕姿项目实现

最近在b站刷到很多关于ai孙笑川唱的歌曲&#xff0c;加上最近大火的ai孙燕姿&#xff0c; 这下“冷门歌手”整成热门歌手了 于是写下一篇文章&#xff0c; 如何实现属于的ai歌手。 注意滥用ai&#xff0c;侵犯他人的名誉是要承担法律责任的 下面是一些所需的文件链接&#xff…

低代码信创开发核心技术(一):基于Vue.js的描述依赖渲染DDR实现模型驱动的组件

前言 随着数字化转型的不断发展&#xff0c;低代码开发平台已成为企业快速建立自己的应用程序的首选方案。然而&#xff0c;实现这样一个平台需要具备高效、灵活和可定制化的能力。这正是基于描述依赖渲染&#xff08;Description dependency rendering&#xff09;所实现的。…