转载

《完爆面试官》系列之Mybatis篇(下)

前言

《完爆面试官》系列之Mybatis篇(下)

​ HR小姐姐带领着我来到一间洽谈室中,眼前只见一张长长的会议桌,环顾四周,我立即找了个面向窗户的位子,这样有利于面试官可以清楚地看见索大的刷脸,然后缓缓地坐下来。HR和我简单的寒暄几句后,递给我一杯水,让我稍等一会,面试官马上就来了。

​ 索大暗暗思道:这个小姐姐人还挺好,有礼貌,声音也很温柔,面试官应该也不赖吧!

面试开始

​ 没过多久,一位身着格子衫+牛仔裤搭配,体型略显瘦高,戴着一个黑框框眼镜的男士,推开洽谈室的门。

​ 索大礼貌性地起身问候:帅气的面试官,您好呀。

《完爆面试官》系列之Mybatis篇(下)

面试官仔细地翻阅索大的简历,来来回回翻了几次,心里暗道:

这家伙,整整写了五页纸,不知道是真有点东西还是凑字数的,待我来考考他吧

你知道mybatis的缓存吗?

《完爆面试官》系列之Mybatis篇(下)

​ 索大对于缓存,有些个人的见解。缓存对于系统性能来说是不可或缺的,使用缓存, 我们可以避免频繁的与数据库进行交互, 尤其是在查询越多、缓存命中率越高的情况下, 使用缓存对性能的提高更明显。

​ mybatis 也提供了对缓存的支持, 分为一级缓存和二级缓存。 但是在默认的情况下, 只开启一级缓存(一级缓存是对同一个 SqlSession 而言的)。

这是一张mybatis的缓存架构原理图,分别包含了 一级缓存二级缓存第三方缓存 的工作流程。

《完爆面试官》系列之Mybatis篇(下)

那你说说什么是一级缓存?

一级缓存

在mybatis的全局配置文件中添加:

<setting name="localCacheScope" value="SESSION"/>
复制代码

默认是SESSION级别 ,即在一个MyBatis会话中执行的所有语句,都会共享这一个缓存。另一种一种是 STATEMENT 级别,可以理解为缓存只对当前执行的这一个Statement有效。

一级缓存指的就是sqlsession,在sqlsession中有一个数据区域,是map结构,这个区域就是一级缓存区域。

​ 一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询的结果。

《完爆面试官》系列之Mybatis篇(下)

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

缓存命中

《完爆面试官》系列之Mybatis篇(下)

缓存未命中

《完爆面试官》系列之Mybatis篇(下)

索大通过查看源码得知,如果是insert/delete/update方法,缓存就会被刷新

《完爆面试官》系列之Mybatis篇(下)
《完爆面试官》系列之Mybatis篇(下)

总结

  • mybatis一级缓存的生命周期和sqlsession一致

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

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

那你再讲讲啥是二级缓存哈?

首先在mybatis的全局配置文件中添加:

<setting name="cacheEnabled" value="true"/>
复制代码

mybatis的映射xml文件

标签用于声明这个namespace使用二级缓存,并且可以自定义配置

代表引用别的命名空间的Cache配置,两个命名空间的操作使用的是同一个Cache

​ 二级缓存指的就是同一个namespace下的mapper,二级缓存中,也有一个map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值

《完爆面试官》系列之Mybatis篇(下)
二级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存被多个SqlSession共享,是一个全局的变量。当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。
复制代码

​ 但是,值得注意的是, 如果不提交事务,二级缓存并不起作用!

二级缓存的常见 应用场景

  • 对查询频率高 ,变化频率低的数据建议 使用二级缓存。
  • 对于访问多的查询请求且用户对查询结果实时性要求不高,此时采用Mybatis二级缓存技术降低数据库 访问量,提高访问速度。

业务场景比如:

  • 耗时较高的统计分析sql

  • 电话账单查询 sql等。

实现方法如下:通过设置刷新时间间隔,由mybatis每隔一段时间自动清空缓存,根据数据变化 频率设置缓存的刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。

总结

  • mybatis的二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,能够到namespace级别。

  • mybatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷。

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

《完爆面试官》系列之Mybatis篇(下)

索大讲到这里,看了看面试官,好像觉得我在不知所云,于是就停止继续往下深入了!

面试官眼睛直勾勾地看着我,欲言又止地说道:

额,小伙子,要不你先讲道这,看来你是真的对mybatis缓存有了解过。

那你对于Mybatis插件的底层原理有了解过吗?

嗯嗯,索大对于mybatis插件之拦截器还是有所知晓的

拦截器的实现原理

​ 是 JDK动态代理和责任链设计模式的综合运用 。采用责任链模式,通过动态代理组织多个拦截器,通过这些拦截器你可以做一些你想做的事。比如: SQL 修改,分页操作,数据过滤, SQL 执行时间性能监控等。

mybatis的四大核心对象

ParameterHandler:处理SQL的参数对象
ResultSetHandler:处理SQL的返回结果集
StatementHandler:数据库的处理对象,用于执行SQL语句
Executor:MyBatis的执行器,用于执行增删改查操作
《完爆面试官》系列之Mybatis篇(下)

Mybatis Plugin 插件源码分析

《完爆面试官》系列之Mybatis篇(下)
《完爆面试官》系列之Mybatis篇(下)

拦截器接口Interceptor

《完爆面试官》系列之Mybatis篇(下)

Plugin代理类

org.apache.ibatis.plugin.Plugin ,实现 InvocationHandler 接口,插件类,一方面提供创建动态代理对象的方法,另一方面实现对指定类的指定方法的拦截处理。

《完爆面试官》系列之Mybatis篇(下)

​ 如果多个插件对一个对象的方法进行拦截 就会产生层层拦截效果 第一个对象的动态代理对象传给第二个插件包装,当执行目标方法的时候先调用第二个插件的intercept 然后调用第一个插件的intercept方法 最后执行真正的目标方法。

《完爆面试官》系列之Mybatis篇(下)

那你工作中有没有用到过mybatis的拦截器?

​ 索大当然在项目实践中使用过拦截器啊,mybatis的拦截器应用场景上文已经提及过,有 SQL 修改,分页操作,数据过滤, SQL 执行时间性能监控等。这里就如何自定义一个拦截器插件,需要注意哪些步骤来做个说明吧。

mybatis 自定义拦截器

需求:我们需要对所有更新操作前打印查询语句的 sql 日志

大致分为三步骤:

  • 实现 {@link Interceptor} 接口

    《完爆面试官》系列之Mybatis篇(下)
  • 添加拦截注解 {@link Intercepts}

    mybatis 拦截器默认可拦截的类型只有四种,即四种接口类型 Executor、StatementHandler、ParameterHandler 和 ResultSetHandler 对于我们的自定义拦截器必须使用 mybatis 提供的注解来指明我们要拦截的是四类中的哪一个类接口 具体规则如下: a:Intercepts 标识我的类是一个拦截器 b:Signature 则是指明我们的拦截器需要拦截哪一个接口的哪一个方法 type 对应四类接口中的某一个,比如是 Executor method 对应接口中的哪类方法,比如 Executor 的 update 方法 args 对应接口中的哪一个方法,比如 Executor 中 query 因为重载原因,方法有多个,args 就是指明参数类型,从而确定是哪一个方法

  • 配置文件中添加拦截器

    拦截器其实就是一个 plugin,在 mybatis 核心配置文件中我们需要配置我们的 plugin :

    <plugin interceptor="itwukong.com.mybatis.plugin.MyInterceptor">
    <property name="username" value="wukong"/>
    <property name="password" value="wukong"/>
    </plugin>
    复制代码

需要值得注意的是: 拦截器顺序 1 不同拦截器顺序: Executor -> ParameterHandler -> StatementHandler -> ResultSetHandler

2 对于同一个类型的拦截器的不同对象拦截顺序: 在 mybatis 核心配置文件根据配置的位置,拦截顺序是 从上往下

面试结束

面试官上下打量着我,毫不吝啬地夸了一句:

小伙子,不赖呀。

这个时候,一定不要激动,可以给个低调奢华的表情

《完爆面试官》系列之Mybatis篇(下)
《完爆面试官》系列之Mybatis篇(下)

总结

​ MyBatis是一款优秀的ORM持久层框架,支持定制化SQL、存储过程以及高级映射。涉及到的知识远不止于此,我们要脚踏实地地去实践,然后理解并掌握其中的原理。

参考资料:

  1. mybatis官网 https://mybatis.org/mybatis-3/

  2. 徐郡明 《MyBatis 技术内幕》

  3. 刘增辉 《MyBatis 从入门到精通》

花絮

以上就是本篇文章的全部内容了,谢谢大家的阅览,各位的支持和鼓励是索大前进的动力,下一篇我

们不见不散。

《完爆面试官》系列之Mybatis篇(下)

码字不易啊,喜欢的话不妨 点赞:+1: 关注 :heartbeat: 分享给朋友:busts_in_silhouette: ,这对我真的很重要呀!

《完爆面试官》系列之Mybatis篇(下)
原文  https://juejin.im/post/5e951a94f265da47f5179372
正文到此结束
Loading...