洛神说看完这篇Mybatis一二级缓存要是你还不会,就送你个学妹!skr

Posted 洛 神

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛神说看完这篇Mybatis一二级缓存要是你还不会,就送你个学妹!skr相关的知识,希望对你有一定的参考价值。

人世仙家本自殊,何须相见向中途。惊鸿瞥过游龙去,漫恼陈王一事无。
嗨,大家好,我是洛神,性别男。一个来自快乐星球的程序员
欢迎大家专注我的公众号【程序员洛神】,不仅分享技术,还会分享生活趣事、体育。

前言

话说前几日,在群里摸鱼时,看到一个可怜楚楚的小妹妹在群里被一帮抠脚大汉围殴,一看,原来是在讨论Mybatis一二级缓存,此时小妹妹正处于下风,英俊潇洒的洛神怎会弃她于不顾?自然是奋不顾身冲上前去挡在好妹妹面前,一边Google一边和这帮大汉对线,奈何洛神我双拳难敌四手,搞得我是左右为男。

正当洛神快要被降伏之际(等等,降伏不是形容妖怪的迈?)。突然一道金光从天而降,让人无法睁眼直视。金光散去之后,地上安静的躺着一本古老的书籍,洛神走上前去,仔细一看,我尼玛,这不是传说中,大禹治水留下的《洛神说看完这篇Mybatis一二级缓存要是你还不会,就送你个学妹!skr》吗?倘若我掌握了这本书百分之一的精髓,这帮匹夫岂能与我为敌?说时迟那时快,洛神盘坐在地上,气沉丹田,运气至全身,慢慢的翻开了这本书:

Mybatis一级、二级缓存

缓存的作用就不多说了,肯定就是为了减少数据库操作次数,降低数据库压力,将查询结果放到缓存中,下次查询直接取结果,提升查询性能。
mybatis是默认开启一级缓存的,二级缓存默认是关闭的。

一级缓存

一级缓存的存储方式是使用了HashMap的数据结构,key值的组成结构:key值本身的hashCode值+sqlid(由数据库生成)+sql语句本身。 value值则是执行结束后映射出来的Java对象。

一级缓存的作用域是一个SqlSession内部,当我们执行查询后,查询的结果会存入到SqlSession为我们提供的一个map结构中,当我们再次查询同样的数据的时候,mybatis会先去sqlsession中查询,如果有就直接存在,没有再去查数据库。但是要注意的是,一级缓存是依赖于SqlSession对象的,当SqlSession消失后,一级缓存也就消失了。

某些情况下SqlSession都会被重建:

1.如果在代码中使用mybatis,没有使用Spring事务,每次请求数据库,都会新建一个SqlSession,所以这个时候一级缓存时没作用的。
2.调用了SqlSession的修改、添加、删除、commit()、close()方法的时候,一级缓存也会被清空。

有的同学可能对图中绿不拉机的东东比较陌生,我顺带着介绍一下介个东东:

Executor是Mybatis的核心接口,所有的对数据库的增删改查动作都是通过这个接口完成的。

Executor的工作内容主要有如下几项:
1.对一级、二级缓存进行处理。
2.用它来获取数据库的连接。
3.创建statement对象。
4.拿着SQL去数据库执行。
5.将数据库返回的结果进行处理。

来,掌声欢迎整整齐齐的Executor一家人闪亮登场! 啪啪啪啪啪啪~~~~~

Executor中定义了执行器的基本操作(增删改查以及事务的提交、回滚、清空缓存等)

接下来是BaseExecutor,它是一个抽象类,也是定义了一些执行器的基本操作。它是除了CachingExecutor之外所有executor的基类(毕竟CachingExecutor是负责二级缓存的,肯定是要面子的啦)。它主要负责处理一级缓存,下图中的localCache属性就代表着一级缓存。当你使用这个executor来做数据处理的时候,如果是查询,它会先看一级缓存里有没有你要查的数据,如果有,就直接返回,如果没有,就会调用下面的子类的方法去获取数据,然后缓存起来(简称白嫖,像你们一样!)。同样的,当SQL是增删改的话,也会清空对应的一级缓存。

BaseExecutor下面有三个子类,我一一简单介绍下,不展开叙述:

1.SimpleExecutor
整个家族里逻辑最简单的一个执行器,拿到sql直接交给StatementHandler去执行,没有额外的骚操作。

2.BatchExecutor
批处理的执行器,通过批量操作来提升执行性能。它的查询逻辑和SimpleExecutor是一样的,但是对于需要增改的SQL,它不会直接执行,而是放到批次里,等到提交的时候统一执行(JDBC的batch操作)。

3.ReuseExecutor
按照语义理解,可再次使用的执行器,指的是statement对象可以再次使用,内部会通过维护一个HashMap来保存statement对象(Key是需要执行的SQL语句,Value则是生成的statment对象),防止statement不断的重建,以此来提升性能。

CachingExecutor
这个是用来管理二级缓存的执行器,它采用了静态代理模式,通过代理一个Executor对象来执行操作。如果发现二级缓存中没有需要查询的数据,那么它就是把这个请求转交给其他的executor来处理,如果它发现要处理的SQL是增删改类型的,那么就会清空整个二级缓存。

你想使用哪个执行器,都是可以在配置文件中进行配置的。

<settings>
    <!--SIMPLE、REUSE、BATCH-->
    <setting name="defaultExecutorType" value="SIMPLE"/>
</settings>

Mybatis如何判断两次查询是否是完全相同的查询?

介个问题问得好,心里能有这个疑问的说明自己在主动思考了,mybatis对于两次查询是否是完全相同的判断,需要满足以下几个条件。

1.传入的statementId要相同。(statement我就不用多说了把,Java就是通过它向数据库发送SQL语句)
2.查询时想要查询的结果的范围要相同。
3.最终传递给JDBC进行解析的sql串要完全相同。
当这个几个条件同时满足后,mybatis就会判定这是同一个查询,就会直接去缓存中查询。

二级缓存

图很重要!先把图给我看十遍!(转载图片请注明出处,感谢)

二级缓存数据应用级缓存,默认是关闭的,开启二级缓存后,mybatis要求返回的必须是可以被序列化的实体。

二级缓存的作用域是同一个nameSpace(别问我nameSpace是啥哈!自己打开自己写的mapper.xml文件,第一行里面就写了),整个nameSpace里的所有语句,都共用同一个cache,换句话说 ,二级缓存被多个sqlSession对象共享。

当执行update/insert等修改方法时,整个作用域的缓存就会失效并重新刷新。

开启二级缓存的方法:
//mybatis配置文件中开启

<settings>     
	<setting name="cacheEnabled" value="true"/>
</settings>
<cache 
  有具体的配置项信息
  eviction  缓存的回收策略,默认是LRU(移除最长时间没有使用的对象) 还有例如FIFO(先进先出,按照对象进入缓存的时间来依次移除) SOFT、WEAK
  
  flushInterval  设置缓存多久刷新一次  默认是不清空的
  
  size  设置缓存里可以存放多少个元素
  
  readOnly  设置是否为只读    设置为true  速度最快  但是不安全 因为maybatis会直接将数据在缓存中的引用交给你
  false的话速度慢  mybatis会通过序列化和反序列化copy一份数据给你
  /> 

一般是不建议使用二级缓存的,因为二级缓存有几个比较大的缺陷,想象一个业务场景:

数据库存放了10000个商品让用户抢购,这个时候访问量肯定是比较大的,所以首先考虑到的肯定就是将商品放入缓存中,那么,假如我们启用了二级缓存后,会发生什么情况呢,第一次查询将数据放到了缓存中,当用户抢购了商品A后,肯定是要刷新商品A的库存的吧,这个时候,如果我刷新缓存,那么,所有商品的信息都会被刷新了,因为二级缓存的作用域是整个nameSpace,本质上就是要死大家一块儿死。所以这个二级缓存很极端的嘞,大家还是谨慎使用。

还有就是,关于脏数据的问题:

洛神一顿操作写了一个完美的SQL

select  a,b,c,d  from  table1   left join table2  on  table1.id = table2.id

可以看出来,洛神是关联两张表查询的(a b字段属于table1 c d字段属于table2),假设哈,这个table1的业务操作都在table1Mapper.xml中 table2的业务操作都啊在table2Mapper.xml中。

我开启了二级缓存,先在table1Mapper.xml中执行了上面的那个SQL,好了,abcd的数据都被缓存起来了,然后,我在table2Mapper.xml中,更新了c和d字段的数据,然后我又在table1Mapper.xml中执行了那个SQL,呕吼,发现问题了吗?由于abcd的数据已经被缓存了,所以我根本感知不到你把c和d的数据改了啊,那不就完犊子了,查出来的数据不就是脏数据了。所以牵扯到联表查询的业务,不要使用二级缓存。

所以在实际业务场景中,对于有缓存需求的功能,都是优先使用Memcache或者redis等缓存中间件来做缓存。一是方便扩容,二是缓存中间件的功能比mybatis的二级缓存强大很多。

诶?那我是不是又可以水一篇Redis和Memcache的文章了?

卧槽,这本书写的,真的是妙蛙种子吃着妙脆角进了米奇妙妙屋,秒到家了!早有幸能看到如此神作,我洛某人何至于此境地,待老夫这就杀他们个片甲不留!对了!我还要将这本神作刻下来,留给世人传颂!
看完这本书你要是还学不会,老夫送你一个学妹!

反正洛神看完这篇文章是湿了,你们呢?

洛神唠点心里话

最近发现爱上了写文章了,也不是为了多少人看,感觉能把自己学习到的,自己知道的东西用比较贯通的语言表达出来,然后每天夜深人静的时候偷偷在被窝里来回欣赏(气氛逐渐变态。。。),看到自己发布在博客上的文章被几百人几千人的浏览,真的感觉挺自豪的,自己写的哪怕能对其他人有一丢丢的帮助,那也算是善事一件啊。

最近几天逛论坛的时候,发现好多人都问,怎么通过写文章变现?我觉得这个问题不能一视同仁。如果你想把它当作一个职业,那你需要具备良好的文字功底,能挖掘用户群众的需求,并且还要具备一定的运营能力,而不是简简单单的每天写写文章发一发。如果你写文章的初心只是为了记录自己的成长,那就别太在乎这些,努力不断学习,不断在工作中打磨自己的能力,等到哪天自己站在这个行业更高的角度的时候,当初你羡慕的东西,都会慢慢归属于你了。
朋友请记住,你若盛开,花香自来。

人世仙家本自殊,何须相见向中途。惊鸿瞥过游龙去,漫恼陈王一事无。我是洛神,我们下期见。

以上是关于洛神说看完这篇Mybatis一二级缓存要是你还不会,就送你个学妹!skr的主要内容,如果未能解决你的问题,请参考以下文章

洛神说看完这篇Mybatis一二级缓存要是你还不会,就送你个学妹!skr

软件测试看完这篇你还不会“接口测试”,你把我吊起来锤!

Android面试储备Activity知识点全家桶;看完这篇你还不会,请给我寄刀片

Android面试储备Activity知识点全家桶;看完这篇你还不会,请给我寄刀片

收藏!最详细的Python全栈开发指南 看完这篇你还不会Python全栈开发 你来打我!!!

别再说自己不会了!知乎超赞回答:Java如何进阶?看完这篇彻底明白了