当前位置:XML > XML介绍

图解聊聊MyBatis缓存

北京哪家皮肤科医院好 https://m-mip.39.net/disease/mip_9278663.html

本文主要内容如下:

一、MyBatis缓存中的常用概念

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

SqlSssion:代表和数据库的一次会话,向用户提供了操作数据库的方法。

MappdStatmnt:代表要发往数据库执行的指令,可以理解为是SQL的抽象表示。

Excutor:代表用来和数据库交互的执行器,接受MappdStatmnt作为参数。

namspac:每个Mappr文件只能配置一个namspac,用来做Mappr文件级别的缓存共享。

映射接口:定义了一个接口,然后里面的接口方法对应要执行SQL的操作,具体要执行的SQL语句是写在映射文件中。

映射文件:MyBatis编写的XML文件,里面有一个或多个SQL语句,不同的语句用来映射不同的接口方法。通常来说,每一张单表都对应着一个映射文件。

二、MyBatis一级缓存

2.1一级缓存原理

在一次SqlSssion中(数据库会话),程序执行多次查询,且查询条件完全相同,多次查询之间程序没有其他增删改操作,则第二次及后面的查询可以从缓存中获取数据,避免走数据库。

每个SqlSssion中持有了Excutor,每个Excutor中有一个LocalCach。当用户发起查询时,MyBatis根据当前执行的语句生成MappdStatmnt,在LocalCach进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入LocalCach,最后返回结果给用户。

LocalCach其实是一个hashmap的结构:

privatMapObjct,Objctcach=nwHashMapObjct,Objct();

如下图所示,有两个SqlSssion,分别为SqlSssion1和SqlSssion2,每个SqlSssion中都有自己的缓存,缓存是hashmap结构,存放的键值对。

键是SQL语句组成的Ky:

StatmntId+Offst+Limmit+Sql+Params

值是SQL查询的结果:

2.2一级缓存配置

在mybatis-config.xml文件配置,nam=localCachScop,valu有两种值:SESSION和STATEMENT

configurationsttingssttingnam="localCachScop"valu="SESSION"//sttingsconfiguration

SESSION:开启一级缓存功能

STATEMENT:缓存只对当前执行的这一个SQL语句有效,也就是没有用到一级缓存功能。

首先我们通过几个考题来体验下MyBatis一级缓存。

2.一级缓存考题

考题(1)只开启了一级缓存,下面的代码调用了三次查询操作gtStudntById,请判断,下列说法正确的是?

//打开一个SqlSssionSqlSssionsqlSssion=factory.opnSssion(tru);StudntMapprstudntMappr=sqlSssion.gtMappr(StudntMappr.class);//根据id=1查询学生信息Systm.out.println(studntMappr.gtStudntById(1));//根据id=1查询学生信息Systm.out.println(studntMappr.gtStudntById(1));//根据id=1查询学生信息Systm.out.println(studntMappr.gtStudntById(1));

答案:第一次从数据库查询到的数据,第二次和第二次从MyBatis一级缓存查询的数据。

解答:第一次从数据库查询后,后续查询走MyBatis一级缓存

考题(2)只开启了一级缓存,下面代码示例中,开启了一个SqlSssion会话,调用了一次查询,然后对数据进行了更改,又调用了一次查询,下列关于两次查询的说法,正确的是?

//打开一个SqlSssionSqlSssionsqlSssion=factory.opnSssion(tru);StudntMapprstudntMappr=sqlSssion.gtMappr(StudntMappr.class);//根据id=1查询学生信息Systm.out.println(studntMappr.gtStudntById(1));//插入了一条学生数据,改变了数据库Systm.out.println("增加了"+studntMappr.addStudnt(buildStudnt())+"个学生");//根据id=1查询学生信息Systm.out.println(studntMappr.gtStudntById(1));sqlSssion.clos();

答案:第一次从数据库查询到的数据,第二次从数据库查询的数据

解答:第一次从数据库查询后,后续更新(包括增删改)数据库中的数据后,这条SQL语句的缓存失效了,后续查询需要重新从数据库获取数据。

考题()当开启了一级缓存,下面的代码中,开启了两个SqlSssion,第一个SqlSssion查询了两次学生A的姓名,第二次SqlSssion更新了一次学生A的姓名,请判断哪个选项符合最后的查询结果。

SqlSssionsqlSssion1=factory.opnSssion(tru);SqlSssionsqlSssion2=factory.opnSssion(tru);StudntMapprstudntMappr=sqlSssion1.gtMappr(StudntMappr.class);StudntMapprstudntMappr2=sqlSssion2.gtMappr(StudntMappr.class);studntMappr2.updatStudntNam("B",1);Systm.out.println(studntMappr.gtStudntById(1));Systm.out.println(studntMappr2.gtStudntById(1));

答案:

AB

解答:只开启一级缓存的情况下,SqlSssion级别是不共享的。代码示例中,分别创建了两个SqlSssion,在第一个SqlSssion中查询学生A的姓名,第二个SqlSssion中修改了学生A的姓名为B,SqlSssion2更新了数据后,不会影响SqlSssion1,所以SqlSssion1查到的数据还是A。

2.4MyBatis一级缓存失效的场景

不同的SqlSssion对应不同的一级缓存同一个SqlSssion但是查询条件不同同一个SqlSssion两次查询期间执行了任何一次增删改操作同一个SqlSssion两次查询期间手动清空了缓存

2.5MyBatis一级缓存总结

MyBatis一级缓存内部设计简单,只是一个没有容量限定的HashMap,在缓存的功能性上有所欠缺

MyBatis的一级缓存最大范围是SqlSssion内部,有多个SqlSssion或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statmnt

一级缓存的配置中,默认是SESSION级别,即在一个MyBatis会话中执行的所有语句,都会共享这一个缓存。

三、MyBatis二级缓存

.1MyBatis二级缓存概述

MyBatis的二级缓存相对于一级缓存来说,实现了SqlSssion之间缓存数据的共享,同时粒度更加的细,能够到namspac级别,通过Cach接口实现类不同的组合,对Cach的可控性也更强。

MyBatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。

在分布式环境下,由于默认的MyBatisCach实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将MyBatis的Cach接口实现,有一定的开发成本,直接使用Rdis、Mmcachd等分布式缓存可能成本更低,安全性也更高。

.2MyBatis二级缓存原理

一级缓存最大的共享范围就是一个SqlSssion内部,如果多个SqlSssion之间需要共享缓存,则需要使用到二级缓存。

开启二级缓存后,会使用CachingExcutor装饰Excutor,进入一级缓存的查询流程前,先在CachingExcutor进行二级缓存的查询。

二级缓存开启后,同一个namspac下的所有操作语句,都影响着同一个Cach。

每个Mappr文件只能配置一个namspac,用来做Mappr文件级别的缓存共享。

mapprnamspac="mappr.StudntMappr"/mappr

二级缓存被同一个namspac下的多个SqlSssion共享,是一个全局的变量。MyBatis的二级缓存不适应用于映射文件中存在多表查询的情况。

通常我们会为每个单表创建单独的映射文件,由于MyBatis的二级缓存是基于namspac的,多表查询语句所在的namspac无法感应到其他namspac中的语句对多表查询中涉及的表进行的修改,引发脏数据问题。

.MyBatis缓存查询的顺序

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用如果二级缓存没有命中,再查询一级缓存如果一级缓存也没有命中,则查询数据库SqlSssion关闭之后,一级缓存中的数据会写入二级缓存。

.4二级缓存配置

开启二级缓存需要在mybatis-config.xml中配置:

sttingnam="cachEnabld"valu="tru"/

.5二级缓存考题

测试updat操作是否会刷新该namspac下的二级缓存。

开启了一级和二级缓存,通过三个SqlSssion查询和更新学生张三的姓名,判断最后的输出结果是什么?

SqlSssionsqlSssion1=factory.opnSssion(tru);SqlSssionsqlSssion2=factory.opnSssion(tru);SqlSssionsqlSssion=factory.opnSssion(tru);StudntMapprstudntMappr=sqlSssion1.gtMappr(StudntMappr.class);StudntMapprstudntMappr2=sqlSssion2.gtMappr(StudntMappr.class);StudntMapprstudntMappr=sqlSssion.gtMappr(StudntMappr.class);Systm.out.println("studntMappr读取数据:"+studntMappr.gtStudntById(1));sqlSssion1.


转载请注明:http://www.vviuov.com/jbzs/1063089.html