Nothing that has meaning is easy. - 有意义的事从来都不是容易的。

Mybatis进阶之揭开二级缓存的神秘面纱(五)

一、前言:

​ 初学java认识那么多数据结构,一到框架,初闻二级缓存,不经瑟瑟发抖,心想框架都如此神秘吗?二级缓存到底是啥?学完本章,一切真相都将浮出水面.

二、回顾CachingExecutor缓存执行器

​ 前面《Mybatis之Executor执行器(一)》中讲述了CachingExecutor缓存执行器,为什么说它是缓存执行器往下瞧.

avatar

​ 由图可看出,CachingExecutor缓存执行器主要是对事务缓存管理器的控制,它并不进行真正的数据存储.

三、TransactionalCacheManager

​ 事物管理器,主要对事物缓存集进行控制,下图可见.
avatar

四、TransactionalCache

​ 事物管理器,主要对事物缓存集进行控制,下图可见.

avatar

avatar

avatar

五、Cache

​ 缓存器,这个就是我们所说的二级缓存,它是一个应用级别的缓存,不懂的看着要懵逼了,这么多Cache缓存器,具体实现哪个啊?小伙伴们不必感到惊慌噢!这是一个缓存器的责任链+适配器,咱们接着往下瞧.

责任链模式:处理相关事务责任的一条执行链,执行链上有多个节点,每个节点都有机会(条件匹配)处理请求事务,如果某个节点处理完了就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕.
摘自:【设计模式】之责任链模式

适配器模式:两个不兼容的接口或对象之间的桥梁,对其进行适配.

avatar

  • BlockingCache - 防穿透缓冲器

    防穿透缓冲器,主要通过重入锁进行线程控制.

    avatar

    avatar

  • SynchronizedCache - 同步缓冲器

    avatar

  • LoggingCache - 缓存命中记录器

    avatar

  • LruCache - 最近最少使用淘汰缓存器

    avatar

  • SerializedCache - 序列化缓存器

    序列化缓冲器,在多个线程获取时为其生成各自的数据副本.

    avatar

  • WeakCache - 弱引用缓存器

    弱引用缓存器,确保有效数据的真实性,此处的垃圾收集队列只做了占位的作用.

    image-20201028000734810.png

  • PerpetualCache - 内存永久缓存器

    image-20201028001802605.png

    这就是神秘的二级缓存啦!看到这里是不是很幸福,嘴角疯狂上扬~,内心感叹 ‘就这?’,没错,就这噢!

六、总结

​ 二级缓存由为主要的是这条执行链,可以对其进行改造并添加新的链节点,Mybatis使用其暂存区也是特别奇妙的地方,必须提交后才对二级缓存进行填充,就是为了回滚后,二级缓存能有效避免脏数据的产生,二级缓存的面纱揭开啦!

IO线程模型之NIO(Reactor)线程模型(二)

一、前言

​ io操作在程序中普遍存在,有三大io线程模型分别为BIO、NIO、AIO,本文将介绍其中的NIO线程模型.

二、NIO(Reactor)线程模型

  • NIO线程模型是什么?

    线程发起 (网络)IO 请求,通过Selector(多路复用选择器)进行注册监听,监听为可读才去通知业务线程,在没有收到真正的处理时业务线程都是自由的,所以NIO称为同步非阻塞式IO.

  • NIO(Reactor)线程模型图解

    avatar

    图解说明:

    ​ 每个客户端会发起一个请求到服务端,通过Selector(多路复用选择器)进行注册并对其进行事件监听,当Selecotr监听到读取事件会生成一个handle处理器异步处理,handle负责读取、通知线程池处理、处理后发送给客户端.

    图解分析:

    ​ 客户端发送请求后注册到Selector(多路复用选择器)

    ​ Selector监听到读取操作时生成handle异步处理

    ​ handle读取消息通过线程池处理该消息,然后再发送给客户端

三、总结

​ NIO(Reactor)线程模型会有一个Selector(多路复用选择器)进行监听,只有存在可读消息才会有对应的业务线程进行处理,应对大流量的QPS,服务器也能应对自如了.

jdbc之statement执行器

一、前言:

​ 本文主要讲述java.sql包下的statement执行器,集成各厂商对其的实现包就可以连接使用其厂商的数据库啦!是不是很神奇,针对mysql我们往下看.

二、Statement执行器

  • Statement执行器关系图

    Wrapper是包装器接口

    AutoCloseable是自动关闭接口

    Statement是执行器接口

    PreparedStatement是预处理执行器接口

    CallableStatement是存储过程执行器接口

    ↓↓↓↓↓↓↓↓ mysql实现 ↓↓↓↓↓↓↓↓

    WrapperBase是基础包装,主要准备连接池、准备异常拦截器、托管子类所需的接口代理缓存

    StatementWrapper是基础执行器包装

    PreparedStatementWrapper是预处理执行器包装

    CallableStatementWrapper是存储过程执行器包装

    avatar

  • Wrapper

    包装器

    avatar

  • AutoCloseable

    自动关闭器

    avatar

  • Statement

    执行器接口

    avatar

  • PreparedStatement

    预处理执行器

    avatar

  • CallableStatement

    存储过程执行器

    avatar

  • WrapperBase

    基础包装,主要准备连接池、准备异常拦截器、托管子类所需的接口代理缓存

    avatar

  • StatementWrapper

    基础执行器包装,特别注意:属性wrappedStmt是Statement接口对象

    avatar

  • PreparedStatementWrapper

    预处理执行器包装,加入了sql脚本的执行操作

    avatar

  • CallableStatementWrapper

    存储过程执行器包装

    avatar

三、总结

​ 学完mysql数据库厂商对Statement处理器的扩展,相信大家对这个statement有了更加深入的了解了,其它数据库厂商也是围绕这些接口做的扩展,妈妈再也不用担心我不了解Statement啦!

Mybatis之jdbc处理器(四)

一、前言:

​ mybatis框架有四大步骤,分别为接口代理、门面会话、执行器、jdbc处理器,本文将针对jdbc处理器进行展开,如果对statement执行器不熟悉的,请先看【 jdbc之statement执行器 】一文.

二、jdbc处理器

  • jdbc处理器关系图

    StatementHandler是jdbc处理器接口

    RoutingStatementHandler是statement的路由处理器,负责生成指定的StatementHandler并路由指定操作

    BaseStatementHandler是基础处理器(抽象类),负责处理子类的共性(设置超时时间、设置读取大小、自动生成主键、关闭statement),它的子类有SimpleStatementHandler(简单statement处理器)、PreparedStatementHandler(预处理statement处理器)、CallableStatementHandler(存储过程statement处理器).

    avatar

  • StatementHandler

    StatementHandler是mybatis中的处理器接口

    avatar

  • RoutingStatementHandler

    statement的路由处理器,主要生成指定的StatementHandler并路由指定操作

    avatar

  • BaseStatementHandler

    基础处理器,负责处理子类的共性(设置超时时间、设置读取大小、自动生成主键、关闭statement).

    avatar

  • SimpleStatementHandler

    简单statement处理器,创建简单执行器。

    avatar

  • PreparedStatementHandler

    预处理statement处理器,创建预处理执行器。

    avatar

  • CallableStatementHandler

    存储过程statement处理器,创建存储过程执行器,注册存储过程的出参.

    avatar

三、存在BaseStatementHandler,为什么还要设计SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler?

​ 可以观看Mybatis之Executor执行器(一)中有讲述.

四、总结

​ 学完jdbc处理器就知道是对statement执行器进行了对应的封装啦!里面的设计还是非常巧妙的,值得各位小伙伴学习哟!

Mybatis之门面会话(三)

Mybatis之门面会话(三)

一、前言:

​ mybatis框架有四大步骤,分别为接口代理、门面会话、执行器、jdbc处理器,前面提及Executor执行器,放在前面是因为它是主要成员,本文将针对门面会话进行展开.

二、门面会话

  • 为啥叫门面会话,为啥不叫装饰会话?

    avatar

    look this!

    张三:SqlSessionFactory为啥要弄这么多方法了,最后都是生成一个sql会话,一个方法不就好了

    李四:是啊,这不写起来更麻烦了嘛,都冗余了

    可不是这样的,这是构造方法重载呀!

    avatar

    所有的方法实现都会指向于openSessionFromDataSource(从数据源中打开会话),接着往下瞧.

    avatar

    张三:看到这里我终于知道我的事务是怎么回滚的了

    李四:我也知道了,所有sql语句执行由Executor执行器处理,开启会话的时候将事务绑定给了执行器,所以我执行出错的语句就由它回滚了

    真聪明啊,2位大佬,没错就是这样,我们来一步步解析看看

    • 首先是我们的获取事务工厂

    avatar

    • 当前环境中没有事务工厂我就生成一个,有就去当前这个,是不是特别简单,没错就是这么简单

    接着看看是如何获取事务

    avatar
    直接生成一个jdbc的事务,要不要这么简单,啊sir,惊呆了吧小伙伴(小提示:当前这个事务是mybatis对jdbc事务的封装)

    • 接着看看是如何生成的执行器

    avatar

    avatar

    关于2次判断可是个小坑,不知道的还以为是代码冗余了,并不是哦,这里还做了拦截功能,以供我们做插件扩张.厉害啊sir

    • 最后创建会话

    avatar

  • 门面会话就这样吗?No,SqlSession登场!

    avatar

    渍渍渍,弄这么多查询方法

    张三:我知道,我知道,这是方法重载

    害,张三呀张三,你看看方法这么多查询方法,不是说单个方法,仔细看看,这是我们的 “门面模式” 呀,你这说得一点排面都莫得.让我们来了解一下什么是门面模式.

    门面模式:是指提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用(=>此话摘取于百度百科).

    张三:我知道它的调用肯定是由Executor执行的

    哦呦!有点东西哦,和小伙伴说说为什么呢?

    张三:前面打开会话的时候,生成了Executor实例,sql语句由Executor执行,没错!肯定就是它了

    你可真机智呀,下面让我们来看看具体实现吧

    avatar

三、总结

​ 门面会话中的坑还是有点的,比如那2行代码,不知道的以为作者写的时候是不是睡着了,里面的设计思想可真是精彩呀!把所有的东西融入到会话中,会话的门面模式调用,简直就是精彩!

Mybatis之接口代理(二)

Mybatis之接口代理(二)

一、前言:

​ mybatis框架有四大步骤,分别为接口代理、门面会话、执行器、jdbc处理器,前面提及Executor执行器,放在前面是因为它是主要成员,本文将针对接口代理进行展开.

二、接口代理

* 模拟Mapper接口,动态代理调用方法

avatar

* 通sqlSession.getMapper(SysUserMapper.class)获得了我们在mybatis中的代理对象,是不是很神奇,让我们往下看,这里做个小提示(当前sql会话为DefaultSqlSession).

avatar
​ * 进入源码我们发现这个方法为我们返回了一个当前sql会话中的一个对应的mapper映射对象.怎么获得的了,继续往下看.

avatar

avatar

avatar

avatar

  • 通过configuration大管家获得mapper,这里做个小提示(configuration是mybatis的配置总站),然后通过mapperRegistry(Mapper接口注册中心)获得mapper,最后直接在注册中心的存储器中获取mapper接口代理工厂.

    张三:这是动态代理

    李四:不,是静态代理

​ 李四:不这是静态代理

​ 是什么代理呢?往下瞧

avatar

avatar

​ 这里生成了一个Mapper的代理对象,先不用管,下面会继续说到,Proxy生成一个静态的代理工厂,帮我们创建动态代理对象,张三值得表扬.

​ 张三:既然是jdk的动态代理,调用mapper.selectAll()底层肯定是用的invoke进行的调用

​ 张三这么自信的回答,各位小伙伴肯定也知道是这样啦!让我们继续看

avatar

​ 好家伙,生成的那个代理对象果然就是你这货.

三、总结

​ 我们现在就可以自信的喊出Mybatis接口代理是用的jdk的Proxy生成的动态代理.

IO线程模型之BIO线程模型(一)

一、前言

​ io操作在程序中普遍存在,有三大io线程模型分别为BIO、NIO、AIO,本文将介绍其中的BIO线程模型.

二、BIO线程模型

  • BIO线程模型是什么?

    线程发起(网络) IO 请求,都会生成一个对应的业务线程,在没有收到请求消息之前业务线程都是阻塞的,所以BIO称为同步阻塞式IO.

  • BIO线程模型图解

    avatar

    图解说明:

    ​ 每个客户端会发起一个请求到服务端,都会生成一个与之对应的线程去处理该请求,该线程会去做一些事(执行程序的一些逻辑),然后将结果进行返回给客户端.

    图解分析:

    ​ 客户端发送请求后,客户端阻塞(等待服务端结果返回)

    ​ 服务端接受到请求后,生成线程处理,处理中有io操作,处理线程阻塞(等待io结果返回)

三、总结

​ BIO线程模型会对每一次请求进行阻塞,直到结果返回,如果因为网络原因或者处理请求缓慢导致大量的请求堆积,服务端可谓不堪重负.

Mybatis之Executor执行器(一)

一、前言:

​ mybatis框架有四大步骤,分别为接口代理、门面会话、执行器、jdbc处理器,本文将针对执行器进行展开.

二、执行器

  • 执行器关系图

    Executor是执行器接口,BaseExecutor是一个抽象类,负责管理mybatis的一级缓存(会话级缓存)逻辑,BaseExecutor的子类有SimpleExecutor(简单执行器)、ReuseExecutor(可重用执行器)、BatchExecutor(批处理执行器),还有CachingExecutor,继承Executor,主要负责mybatis的二级缓存(应用级缓存).

    avatar

  • Executor

    Executor是mybatis中的执行器接口

    avatar

    avatar

  • BaseExecutor

    基础执行器,主要职责mybatis的一级缓存(会话级缓存),增、删、改都会清空一级缓存,下面看一下BaseExecutor的基本成员变量.

    avatar

  • SimpleExecutor

    简单执行器,每次都会创建一个StatementHandler(Statement处理器)进行查询.

  • ReuseExecutor

    可重用执行器,内部会创建一个statementMap,用来缓存每次执行的sql语句创建的statement,从而达到复用.

    avatar

  • BatchExecutor

    批处理执行器,每次增、删、该操作会将sql语句创建的statement缓存到内部的statementList中,

    调用doFlushStatements才是真正对sql进行执行,将结果数据缓存到内部的batchResultList中,最终才能获取到执行结果

    avatar

  • CachingExecutor

    缓存执行器,主要职责mybatis的二级缓存(应用级缓存),包装Executor执行器,通过TransactionalCacheManager(事务缓存管理器)对当前的Executor进行二级缓存逻辑处理.

    avatar

三、存在BaseExecutor,为什么还要设计SimpleExecutor、ReuseExecutor、BatchExecutor?

​ mybatis的Executor体系思想为单一职责,如果将SimpleExecutor、ReuseExecutor、BatchExecutor放入其中,不由思索,BaseExecutor量太大,所做事情形同一个人做几个人的事情,所以这种单一职责设计是不是可以灵活运用,解决代码堆积在一个类的问题.

四、总结

​ 通过上面的了解,我们已经初步认识到mybatis中的Executor各大执行器,其中单一职责设计不由感到妙啊!细心的小伙伴已经发现了CachingExecutor中的delegate, 不知名会发现这是啥,其实这是装饰了Executor,没错这就是装饰器模式.

​ 切记BaseExecutor的一级缓存是会话级别的哟,增、删、改都会清空一级缓存,CachingExecutor的二级缓存是应用级的.

请我喝杯咖啡吧~

支付宝
微信