当前位置: 首页>后端>正文

一口吃个胖子,吃透Mybatis

什么是Mybatis

CRUD框架,面向数据库开发的脚手架。它提供了支持CRUD操作,还具有以下特性。

Mybatis这套框架的核心在于遵循到位了开闭原则,里氏替换原。组件思想,抓核心思想等。

Mybatis分为三大组件:SQL组装层,数据处理转换层,插件管理层。

Mybatis的核心对象有:BoundSQL,Configuration,SqlSession,MapperProxy,StatementHandler.
一张图描述下查询List的几个步骤


一口吃个胖子,吃透Mybatis,第1张
list.jpg

查询在mybatis大概执行过程,"↓"表示下一个执行片段。

SqlSessionFactory

↓ 创建SqlSesssion,SqlSession相当于Mybatis的执行引擎 预装载datasource,进入configuration,

注意Datasource如果是在依赖注入容器里,也是Singletone模式的

Configuration

根据ID在configuration里面找到相应的命名空间维度的配置项,Mybatis设计上基本都是一次初始永久使用的,交给mapperProxy代理去处理,MapperProxy处理类由它的工厂类MapperProxyFactory创建

MapperProxy 执行invoke,这里面有个cache机制

找到MapperMethod触发execute,里面有根据SQLCommandType去路由到不同的处理方式

SqlSession insert() or update()

Plugin 是否有Plugin机制

RoutingStatementHandler 路由处理

ParameterHandler 执行参数处理,

ResultHandler 结果集处理,游标处理。映射成返回对象

DebuggingPrintLog 有开启Debug日志才会代理Stmt 或者Psmt或者 Result代理

TransactionHandler 关闭事物,如果有Spring食物切面就会托管给它去做这个事情

Spring事物代理切面处理器

*可拓展

*调用链短

*支持内存分页

*手动SQL,满足对SQL性能有要求场景

SQL支持面向语言用注解方式进行组装,或者用ONGL的方式将SQL逻辑表现在XML语言文档中

*Mybatis不像Hibernate是一个真正的持久化框架,HBT更像是弱化了SQL这一基础技能属性。MB的SQL始终是具备完整性的。

*该框架提供了别名机制,别名可以外部配置然后在运行阶段一次性加载到全局的configuration中

Mybatis代码非常精简,上手非常容易。源码理解程度除了ONGL这块比较抽象,其他部分都很容易理解,本文也是化烦为简地方式来讲解,适用于初学者和老手。Mybatis是Web开发里面最简单的框架,很容易了解到原理。

如何快速理解一套框架,我的建议是把它当做一个工具集,既然是工具,先理解它的构造和设计原理,先通过官网描述了解它实现了什么功能,这些功能分别是什么,然后可以以架构师的角度去了解它的作用场景。

当了解了以上这些后,再去庖丁解牛的方式去解开它的内部构造,一般高级语言实现的一个框架在代码的结构上都是分包的,接着去了解它每个包的作用域,然后再去抽象出它所用到的设计模式。考虑一下为什么要用到这个设计模式,当了解了这些之后,就可以上升到如何用好和拓展这个框架了。

*设计模式:

包装器(Wrapper关键字的类群体),JDK动态代理模式,Cglib代理模式。(MapperInterface类),静态工厂模式(SqlSessionFactory,
LoggingFactory,
MapperProxyFactory),建造者模式(包含关键字builder的类),策略模式(隐藏式设计模式,缓存策略模式,日志输出策略模式,StatementHandler模式,使用者不需要关注处理细节,只需要告诉Mybatis你要做什么,只需要体现使用者的行为即可),装饰器模式,ONGL中用到了组合模式(<if>,<else><choosen>等组合tag),Plugin衍生的使用拦截器场景使用的责任链设计模式等(拦截器就是All-in-List then execute-stepbystep-in-chainGroup)。

模拟通讯服务上的路由器的网络分发功能实现的策略模式:

通过RoutingStatementHandler类就是一个路由器,然后通过StatementType类型来决定跳转到不同的handler。

*包结构

排名不分先后顺序

annonations:注解SQL的,作用于SqlBuilder使用场景

binding: 实现Mapper的绑定,里面有个MapperRegister

builder:构造Mapper,解析Configuration的基础配置等

cache:缓存包,装饰器模式。比如与依赖注入控制反转框架Spring使用时要以外部注入装载的方式引入redis等缓存中间件。

cursor:游标,获取Jdbc游标的迭代位置

datasource:数据源[jndi数据源,普通数据源(BasicDatasource)],基于数据库驱动包的条件下,才能ping上对应的数据库,同时,需要设置链接,链接的必要属性一般都是要用户名和密码认证通过才可以。

下面是一个jdbc接口和数据库交互的大致过程~
加载jdbc驱动包->创建链接->开启会话->开启事物->创建statement->读场景游标方式迭代结果集->关闭statement->写场景关闭事物->_遇到异常回滚事物

exceptions:异常包,这部分使用到了是factory model。

executor:支持JDBC操作的入口包

plugin:插件包,通常基于插件机制可以实现分页,SQL执行效率上的性能监控。

IO:流处理

session: JDBCSession等

logging:日志组件,开启debug模式时,针对Statement和result进行了打印日志的代理拦截,不影响原来的流程,该怎么往下执行还得继续。

transaction:事务包,mybatis对事物这块简单地加工了一下,可以支持强制关闭操作等行为

parsing:sql语句转换包

scripting:脚本包

type: JDBC type handler

mapping: 映射包。鉴别器,boundSQL,resultMap,这个包里面涵盖了

sql属性维度,columnType维度,resultMap等维度与ONGL之间的映射模型。这里面几乎都是PlainObject,几乎没有行为透露和传播。

reflect:反射机制包,针对数据库字段提取出值,通过反射机制映射到property字段里。

获取反射类内部用了取出一次就缓存的动作的。

核心类

Confiuration:Mybatis的核心配置类,顶层类,xml配置项,由XMLConfigurationBuilder提供解析装载。它提供你全局获取ResultMap,获取MapMethed.

MapperRegister:注册Mapper类。

SqlSessionFactory:通过build创建sqlSession,需要自定义一个datasouce,

比如集成到Spring框架中时会先定义一个DataSource。

BaseExecutor:执行 insert,update,select

,delete操作。Mybatis严格按照jdbc的CRUD操作返回的类型进行一一对应设计。

MapperProxy:代理类,用jdk动态代理机制,创建字节码方式。XML可以不需要定义接口,但是定义接口就必须要它所包含的package全路径需要是正确的路径。

ResultTypeHandler:Jdbc中的ResultType映射成返回ResultType使用的Java类型。Mybatis定义了自己的JdbcType,为什么它不fixed对应的Java类型,这是基于开闭原则,因为用户拿到的type尤其是char这样的类型丰富多变。它有个TypeRegister机制,用户可以定义自己的type作用于rst.

SqlSesession:就是用来处理connection,connection的处理流程是:开启事物,创建stm或者pstm或者callstm,获取结果集返回的游标,关闭事物(遇到异常抛出来)

CacheProvider:缓存提供者,MB提供了namespace作用域缓存和sqlsession两种缓存作用域。用装饰者设计模式设计出来了多种不同方式的缓存机制。缓存是个多余的设计,不满足业务场景,一般业务层应用开发都单独使用缓存中间件。比如Spring+redis实现。如果业务上的数据只需要隔离数据库,可以实现它的cache接口,用redisCache,用静态方法获取静态注入的RedisSessionFacotory来使用。

,,,

doPut ();
clear();
update();

,,,

一口吃个胖子,吃透Mybatis,第2张

ResultMap:核心类,它的上层是namspace,namespace实际上是存在于xml中,ResultMap是结果集映射,它的是结构化的,语义上的表现结构是由property与associate,collection组成。这些ONGL语言标签由mybatis解析。RSTM它对应的是一个map容器存在。从另一个角度来说,该框架一部分是语义型,一部分是将语义结构化的部分用组件的方式一一抽离出来的。

它的Id是由上往下一直到parameter组装的字符串形式。它是放在一个Map容器的。当SqlSessionFactory完成build以后,mybatis需要的config->作用的对象,cache生成,日志形式等就随着build动作结束以后完成所有的初始化了。

StatementHandler:处理statement,jdbc基础知识,可以预处理,存储过程或函数处理。

PooledConnection:简单地实现了连接池,池化的关键是基于线程池创建管理数据库链接池,一方面减少线程上下文切换奢侈开支的同时又,另一方面又复用了数据库连接池。它里面会检测坏的连接池,坏链接会专门管理,复活会重新使用。对于它里面的设计只需要改进连接池队列和利用aqs来更高的处理就可以演化成一个好用的连接池。

*特性

1.事务性

2.SQL日志
SQL日志可以用拦截器的方式美化query和update的语句。

3.Plugin特性(指定签名方法进行拦截,可以实现SQL性能监控,分页,租户等机制),mybatis支持多个plugin同时存在,没有严格意义上的先后执行顺序,由定义顺序来决定的,业务上有需要的场景有:分页功能,数据加密,防止SQL注入,schema鉴定(比如mybatis拿到用户域以后可以指定用户的schema,SQL性能监控,慢查询直接中断查询,但是就算关闭链接,数据库的任务也不会终止)

4.缓存机制(namespace层,SqlSession粒度的缓存,一个是作用域在命名空间,一个作用域在session粒度).
关于缓存,Mybatis里面提供了LRU缓存机制,如果感兴趣的朋友可以自行实现。因为缓存不是Mybatis的重要属性

下面如何添加一个FILO缓存代码示例

importjava.util.Deque;

importjava.util.LinkedList;

importorg.apache.ibatis.cache.Cache;

/**

* FILO (first in, last out) cache decorator.

*

* @author mybatis

*/

publicclassFifoCacheimplementsCache{

privatefinalCachedelegate;

privatefinalDeque<object>keyList;</object>

privateintsize;

publicFifoCache(Cachedelegate) {

this.delegate=delegate;

this.keyList=newLinkedList<>();

this.size=1024;

  }

@Override

publicStringgetId() {

returndelegate.getId();

  }

@Override

publicintgetSize() {

returndelegate.getSize();

  }

publicvoidsetSize(intsize) {

this.size=size;

  }

@Override

publicvoidputObject(Objectkey,Objectvalue) {

cycleKeyList(key);

delegate.putObject(key,value);

  }

@Override

publicObjectgetObject(Objectkey) {

returndelegate.getObject(key);

  }

@Override

publicObjectremoveObject(Objectkey) {

returndelegate.removeObject(key);

  }

@Override

publicvoidclear() {

delegate.clear();

keyList.clear();

  }

privatevoidcycleKeyList(Objectkey) {

keyList.addLast(key);

if(keyList.size() >size) {

ObjectoldestKey=keyList.removeLast();

delegate.removeObject(oldestKey);

    }

  }

}

5.支持ONGL的SQL写法,支持SqlBuilder以注解形式组装 写SQL,然后表现形式 以显示在方法上

6.支持拓展,比如国产化的Mybatis-Plugin框架,这个框架就是改变MapperBuilder这个内部机制的基础上将单个表的增删改查方法嵌入在SqlMethod里面了。这个框架还实现了低代码思想,并支持Stream流式写法。

7.写了一个不支持高并发的链接池,低吞吐量用户量少时可用

一句话结束

Mybatis是JAVA-Web开发中国内最流行的一套面向数据库开发的框架,它是一款面向对象设计思想的框架。简单易上手,深受广大各个级别的程序员喜爱。

问:How to designe a new framework that is better than mybatis.

问:What is the lack functions of current mybatis-plugin

问:How to avoid restart the web application when some resources ref mybatis has changed by user

答:定义FileChangeListern事件,监听文件。先找到修改文件对应的MapperInterface,指定它重新注入mapper,用MapperRegister重新注册。


https://www.xamrdz.com/backend/3a71923373.html

相关文章: