Mybatis的源码初步理解——四大内置对象

一、对Mybatis框架的简单介绍

  • Mybatis是一个半ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只关注 SQL 语句本身,不需要反复的去处理加载驱动、创建连接、创建 Statement 等繁杂的过程。程序员直接编写原生态 SQL,可以严格控制 SQL 执行性能,灵活度高。

  • MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

  • 通过 XML 文件或注解的方式将要执行的各种 Statement 配置起来,并通过 Java 对象和 Statement 中 SQL 的动态参数进行映射生成最终执行的 SQL 语句。

二、回顾原生JDBC

(图片1)

使用原生JDBC完成ORM的缺陷

存在大量的冗余代码。
手工创建 Connection、Statement 等。
手工将结果集封装成实体对象。
查询效率低,没有对数据访问进行过优化

三、回顾原生Mybatis的使用 - 以Mybatis的执行源码解读,带入Mybatis的四大内置对象

(图片2)

(图片2)中我们可以很清楚的看到,SqlSession.getMapper(),是一个接口,很显然我们无法调用接口的方法,也就意味着,SqlSession.getMapper()底层帮我们实现了JDK动态代理,赋予了接口的实现类。而通过学习动态代理时,我们清楚在这过程中,我们想了解代理类做了什么事情,需要进入invoke方法得知(图片3)

(图片3)

(图片4)

当前(图片4)通过源代码的解读,很容易得知是针对Sql语句的功能(增删改查)进行排查,而Mybatis通过Mapper.xml中我们定义的标签[select、update]等进行排查比较得出结果,不同功能的Sql执行不同的case,这里我们以SELECT(查询为例)-(图5)

(图片5)

(图片6)

当前(图片5)可见我们通过方法的返回值判断,由于我写的sql查询的是单个,所以我们将执行selectOne,进入该方法之后(图片6),会发现我们始终会执行到selectList,再经过长度的判断来返回不同的返回值.

(图片7)

selectList是一个多方法的重载(图片7),最终会发现selectLsit的核心代码是excecutor.query(),所有的Sql语句无论如何代理,无论是增删改查,最终都是会交给excecutor执行器进行处理,query()方法负责查询,update()负责增删改,这也是要引入的四大内置对象之一。(图片8)

(图片8)

四、介绍Mybatis的四大内置对象

四大内置对象① Executor执行器:

是真正执行Java和数据库交互的对象,(图片8)得知,Executor执行器是一个接口,(图片9)记录着Executor接口的关系。

Executor接口的关系图如下:

(图片9)

BaseExecutor:是一个抽象类,采用模板方法的模式。实现了Executor接口,实现执行器的基本功能。

CachingExecutor:在Mybatis的执行过程中,本质上使用的是CachingExecutor缓存的Executor。CachingExecutor采用装饰者模式,继承Executor的同时还持有 Exector的对象,主要起到增强的功能。

SimpleExecutor:简单的执行器,根据对应的SQL直接执行即可,不会做一些额外的操作;拼接完SQL之后,直接交给 StatementHandler 去执行。刚刚我们提到经过Excutor的处理,所有sql的操作最终会交给query()与update()处理,但是在SimpleExecutor中并没有这两个方法,由此得知,该方法在BaseExecutor中,而通过查找BaseExecutor查找,最终会调用queryFromFatabase()方法中的doquery()方法,再进行深挖,会发现该方法是抽象方法,父类的抽象方法实际调用的是子类方法,所以说,最终的所有处理都会汇总到SimpleExecutor中。(图片10)

BacthExecutor:批处理执行器,用于将多个SQL一次性输出到数据库,通过批量操作来优化性能。通常需要注意的是批量更新操作,由于内部有缓存的实现,使用完成后记得调用flushStatements来清除缓存。

ReuseExecutor:可重用的执行器,重用的对象是Statement(),也就是说该执行器会缓存同一个sql的Statement,省去Statement的重新创建,优化性能。内部的实现是通过一个HashMap来维护Statement对象的。由于当前Map只在该session中有效,所以使用完成后记得调用flushStatements来清除Map。调用实现的四个抽象方法时会调用 prepareStatement(数据库操作对象)

(图片10)

我们依旧查询为例,讲解SimpleExecutor(图片11)中的doQuery()与doUpdate(),在doQuery()中,

[这里要重点复习原生JDBC连接数据库的写法,作为参照更好理解,可看(图1)]

Configuration通过xml加载出来的核心配置对象,通过Configuration.newStatementHandler() 进入会发现该方法会获得StateHandler(),(图片12)参照原生JDBC中,就是获得Statement操作对象这个步骤。

(图片11)

(图片12)

四大内置对象②StatementHandler - Statement处理器:

数据库会话器,帮助我们创建Statement,相当于JDBC中的Statement(PreparedStatement)

通过(图片12)在创建Statement处理器时,会创建一个RoutingStatem,该对象也是一个装饰者模式(图片13),通过ms.getStatementType类型来判断应该创建以下那种类型的StatemHandler(JDBC底层一共三个StatemHandler)

SimpleStatementHandler()———对应jdbc中的Statment(存在sql注入的缺点)

PreparStatemenHandler()———对应jdbc中的PreparedStatement(Mybatis默认使用)

CallableStementHandler()———对应jdbc中的CallableStatement(执行存储过程)

(图片13)

当我们想切换Statemen类型时,我们在Mapper.xml的标签中,使用关键字 statementType即可修改

通过继续解读(图片12),(StatementHandler)interceptor.PluginAll(StatemHandler)

该代码是所有插件开发的核心,会将所有插件组装到当前的内置对象中,也是一个动态代理,进行增强的过程。

四大内置对象③ParameterHandler:

是用来处理SQL参数的,参照原生JDBC步骤中,为设置参数步骤

通过继续解读doQuery()方法,执行到PreparStatement中进入该方法,我们可以看到又交给了Prepare()方法,(图片15)在该方法中,完成了对连接对象的实例。

(图片14)

(图片15)

ParameterHandler 由实现类DefaultParameterHandler执行,使用TypeHandler将参数对象类型转换成jdbcType,完成预编译SQL的参数设置。TypeHandler该方法在复杂的ORM情况下,为我们提供了类型转换。(图片16)

(图片16)

四大内置对象④ResultSetHandler:

ResultSet处理器,处理返回结果集

ResultSetHandler接口只有一个默认的实现类是DefaultResultSetHandler,我们通过SELECT语句执行得到的结果集由其 handleResultSets() 方法处理,最终将结果集打包封装,代码解析如下

五、Mybatis的执行流程图形汇总

六、总结:

通过熟悉原生JDBC,再针对Mybatis四大内置对象的区域功能进行比较,会发现其实作用大同小异,就能很好的理解四大内置对象在Mybatis执行中的作用。以上是我作为一个java萌新对Mybatis的浅闻小见,有不正确的地方,还请各位大佬指定讨论,谢谢!!!!!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值