Mybatis源码分析系列之第三篇:Mybatis的操作类型对象

简介: Mybatis源码分析系列之第三篇:Mybatis的操作类型对象

前言知识汇总

上篇文章中我们已经详细介绍了Mybatis的存储类对象。我们上篇提到了:

Mapper.xml当中的SQL标签都被解析成了一个一个的MappedStatement对象。那么我们当中的SQL是基于什么形式进行封装的呢?

我们要知道,Java当中一切皆对象。MappedStatement当中SQL被封装成了MappedStateMent当中的SqlSource对象。

我们通过sqlSource.getBoundSql()来获取一个BoundSql对象,BoundSQL当中的对象就是对于SQL语句的真实封装。

Cofiguration也好,MappedStatent也好存储的是我们配置文件或者是在注解当中书写的配置信息。它们是一个存储对象。

我们还要有操作类型的对象。

一:操作类型对象

1:Excutor

Excutor是执行器的意思,什么是执行器,执行器就是完成各种操作的对象。它是Mybatis当中处理功能的核心。

增删改和查都在Excutor当中都提供了相应的方法。

我们在不了解Mybatis的时候,我们认为Mybatis的当中我们使用的是SqlSession,但是实际上。真正执行各种操作的是Excutor。

SqlSession仅仅是一个门面,它会调用Excutor完成对应的操作。

我们说Excutor是完成Mybatis中操作对象的核心。他是一个接口,我们从接口实现当中可以看到具体的功能点的
我们基于alt+7可以查看我们所有的方法

提供了两类最为核心的方法update && query,注意我们在编程当中的增删改,统一都叫update,而query完成的是查询的操作。

增删改查不就对应了操作数据库的几种方式嘛,另外还有跟事务相关的方法和以及跟缓存相关的方法,这些就是Mybatis当中的所有的操作了。在我们还没有关注Mybatis源码的时候,我们一直以为是由SqlSession来完成的,但是现在显而易见,完成这些操作的应该是Excutor

A:Excutor功能

1:增删改查

2:事务操作(提交、回滚)

3:缓存操作

B:Excutor为什么是接口

未来开发设计之后,我们拿到一个全新的功能之后,我们不知道怎么设计。我们这里有一个规范,但凡是操作相关的类型,我们都需要设计成接口。就比如我们的SqlSession也是一个接口。

设计成接口也是为了提供一种规范,我们在这种规范下可以有不同的实现,也就是不同的实现类类适配不同的业务场景

C:Excutor三个实现类

BaseExcutor仅仅是一个适配器,仅仅提供了一些基本的功能。真正的核心的实现类最为核心的三个实现类是:

值得注意的是最常用的执行器往往是最简单的这个:SimpleExecutor,完成常规的操作,这个是最核心的Excutor,这要是Mybatis当中内置推荐的执行器。如果我们不更改配置的话,默认使用的就是Configuration当中的简单的Excutor

Configuration三个功能:封装Mybatis-Config.xml,存储MappedStatement,创建其他的核心执行的对象包括Excutor,所以配置肯定也在这个类里边。

ReuseExcutor这是一个复用Excutor,他复用的是Statement。我们说任何对数据库的操作底层都得用JDBC,JDBC中的三大件东西Connection是连接数据库的ResultSet是获取查询结果集的,真正和数据库交互的是Statement。复用Statement在什么条件下会发生呢?

Statement与什么想关呢?Statement是与SQL语句相关的。如果我们的SQL在任何条件下都不会改变的话,我们这样的话就可以一直使用这个Statement对象,减少了对象的创建,保证了性能。

这个SQL语句的话可以是增删改查任何的语句,但是不能有任何的改变,任何的改变的话,就不适用了。

BatchExcutor是一个批处理的执行器,我们知道在JDBC当中就有批处理的操作,如果我们想再JDBC当中仍然有批处理的操作。使用这个BatchExcutor即可。也就是一个Connection处理一坨SQL语句,我们就可以考虑使用这个执行器了。

JDBC当中的批处理是啥意思?

我们最简单的JDBC是获取一个Connection之后,我们直接获取一个Statement对象,然后拿着这个对象和数据库沟通,然后取到结果集,释放连接。但是这样会有一个问题,需要频繁的有连接的创建和关闭。或者是连接池的获取和归还。

我们想到了批处理,也就是在一个连接之上,与数据库进行多语SQL交互,这样的话我们就省略了大量的Connetion的创建和销毁,这就是批处理,大大提高了性能。

站在Mybatis当中如果我们想要使用批处理的话,我们就可以使用BatchExcutor

为什么说IO,连接都是非常真贵的资源?

我们知道,我们搞Java开发我们底层面临的是OS操作系统的资源,在它之上我们构建了一个Java虚拟机的东西。我们写Java程序是运行在虚拟机层面上的东西,然后我们想要在虚拟机当中去建立网络连接、或者是io、或者是线程的时候,这个时候虚拟机就办不到了,需要去沟通操作系统,因为只有操作系统可以进行读取文件,可以去访问互联网,只有操作系统可以操作CPU操作线程、进程。所以,我们知道这些操作被后都有操作系统,都会有这些native的方法的操作,而这些东西都是耗时和占用资源的,所以我们认为这些东西,必须要管,必须要复用,必须要池化。

Excutor来处理和数据库的操作,那么这个是怎么和JDBC建立连接的呢,这就和后面的对象有关系了。

2:StatementHandler

这个是真正与数据库建立联系的对象。他是怎么和数据库建立联系的呢?很简单,他直接与JDBC当中的Statement建立联系。Excutor调用StatementHandler,而StatementHandler当中封装了Statement,这样Excutor就可以真正的与数据进行交互了。

A:作用

StatementHandler是一个接口,他的作用就是分担了Excutor中的增删改查。实现真正的JDBC操作。

是Mybatis封装了JDBC Statement,真正MyBatis进行数据库访问的核心。

这里有一个疑问,为什么不能直接把Excutor省略掉,直接使用StatementHandler这里为什么又包了一层呢?

Excutor当中有三件事:增删改查、事务、缓存。把集中的第一部分操作交给了StatementHandler。这里为什么要使用包装,一个类型包装另外一个类型,是为了符合功能单一原则。

完成对数据库的操作,包括了增删改查,还有批处理,还有获取SQL,还有对于SQL参数的处理,所以他的主要工作就是对于数据库的操作。

B:StatementHandler实现类

这里有很浓重的适配器设计模式的痕迹,会有一个BaseStatementHandler草草的实现一些基础功能。关键的类还是三个:

PreparedStatementHandler、SimpleStatementHandler、CallableStatementHandler这里和JDBC中的Statement是严格对应的。

@Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    String sql = boundSql.getSql();
    statement.execute(sql);
    return resultSetHandler.<E>handleResultSets(statement);
  }

3:ParameterHandler

这个的作用就是将Mybatis的参数转换为JDBC的参数,

@Param —> #{} — > ?

后边会有详解…

4:ResultSetHandler

A:作用

这个的作用就是将JDBC当中的查询结果集ResultSet进行了封装。

为什么这里处理结果集对象的入参是Statement?

这是很简单的,在JDBC的操作中,我们必须得有Statement才能获取ResultSet。

在Idea当中如何快速看他的实现类:鼠标放到类名上:Ctrl+Alt+B即可,鼠标翻到方法上,直接Ctrl+Alt+B也可直接到方法。

后边会有详解…

5:TypeHandler

A:作用

他的作用就是类型的梳理,当前我们使用Java程序操作数据库,这里边管的就是数据库类型和Java类型转换的过程。

类型一定是和参数和返回值息息相关的。所以,这个类在两个Handler的下边。

后边会有详解…

二:Mybatis核心对象是如何和SqlSession建立联系的?

我们知道SqlSession会调用Excutor进而调用StatementHandler…来完成具体的操作,那么这个怎么证明呢?他们的联系是怎么进行建立的呢?

上篇文章中我们提到, Mybatis基础开发都会进行这样的操作:

Mybatis开发一开始最基础的构建一定会处理上红框中的代码。将这些进行封装,这些操作最终的目的就是为了获取SqlSession

我们还说过,Mybatis有两种操作数据的方式:直接获取Dao实现类的方式和直接调用SqlSession当中方法的实行去进行调用。第二种的方法是最为底层的方式。第一种方式本质上是第二种开发的封装,基于代理设计模式。最终的本质Mybatis处理S进行开发的方式一定是第二种。我们直接研究第二种代码的调用关系就清楚了,最底层的代码一定是第二种方式,第二种方式才是实实在在Mybatis的方式,第一种的变成方式底层也是由第二种来完成的,我们如何证明呢:

先讲一个看源码时十分有用的操作:

sqlSession.insert(......)   -- 想看insert 方法的源码,Ctrl+B,进来发现是接口,Ctrl+Alt+B查看对应的方法的实现。
总结:看方法调用源码是Ctrl+B,看实现类源码是:Ctrl+Alt+B
以上操作前提都得是光标在对应的类、方法名上。
如果想回去怎么办?
回去的快捷键:Ctrl+Alt+左右健
我这发现了一个变量,我想看他的变量定义怎么办?Ctrl+B

有了以上的宝贝知识,我们在看源码的时候,就不会乱崩了。

Mybatis源码当中的核心对象是在SqlSession调用对应功能的时候建立联系。假设我问要做insert操作:

197行去拿了MappedStatement对象,其实就是拿了Mapper.xml里边的某一个insert标签,而我们知道标签中有SQL,MappedStatement当中有BoundSQL对象。

198行,拿着我们的Statemen交给了Excutor的update方法去执行insert操作。默认情况下这里的excutor一定是SimpleExcutor

看到这里应该所有的操作都清晰了。

总结一下:

三:代理的方式是怎么建立联系的?

第一种方式是代理设计模式,那么第一种是怎么通过代理设计模式就把上边这种UserDao.insert(…)这种方式变成了上述的这种编写方式的呢?

这是我们现在要研究明白的核心,我们只要把这块再研究明白了,实际上Mybatis底层运行的核心,我们就都玩明白了。

这里是一种典型的动态代理设计模式,我们如何一眼看出来这里是代理设计模式,代理设计模式是基于接口在为原始类做一个新的实现,或者干脆就搞出来一个新的实现类。我们搞Mybatis的时候基本上没有用过UserDaoImpl自己写,都是生成的他的对象。

这里如何创建一个代理对象,我们如何写呢,我们不实用Mybatis为我们提供的。我们只需要实用我们之前提到的动态代理的开发即可。

类加载器我们借一个就行,接口就是我们定义的接口,InvocationHandler是我们的额外功能的存放的地方。基于这种方式一定可以实现我们的动态代理。

相关文章
|
3月前
|
Java 数据库连接 数据库
mybatis查询数据,返回的对象少了一个字段
mybatis查询数据,返回的对象少了一个字段
197 8
|
14天前
|
SQL Java 数据库连接
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。本文讲解了最新版MP的使用教程,包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段等核心功能。
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
|
6月前
|
XML Java 数据库连接
【MyBatis】MyBatis操作数据库(一)
【MyBatis】MyBatis操作数据库(一)
53 1
|
6月前
|
XML Java 数据库连接
如何使用 MyBatis 来进行增、删、改、查操作
如何使用 MyBatis 来进行增、删、改、查操作
224 2
|
6月前
|
SQL 存储 Java
基于MyBatis的增删改查操作
基于MyBatis的增删改查操作
43 1
|
2月前
|
SQL Java 数据库连接
mybatis使用四:dao接口参数与mapper 接口中SQL的对应和对应方式的总结,MyBatis的parameterType传入参数类型
这篇文章是关于MyBatis中DAO接口参数与Mapper接口中SQL的对应关系,以及如何使用parameterType传入参数类型的详细总结。
39 10
|
2月前
|
Java 数据库连接 mybatis
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
该文档详细介绍了如何在Springboot Web项目中整合Mybatis,包括添加依赖、使用`@MapperScan`注解配置包扫描路径等步骤。若未使用`@MapperScan`,系统会自动扫描加了`@Mapper`注解的接口;若使用了`@MapperScan`,则按指定路径扫描。文档还深入分析了相关源码,解释了不同情况下的扫描逻辑与优先级,帮助理解Mybatis在Springboot项目中的自动配置机制。
139 0
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
|
2月前
|
SQL Java 数据库连接
Mybatis中传入不同类型的值处理方案
这篇文章讲述了在Mybatis中如何处理传入不同类型参数的情况,包括单个值、列表及Map等,并提供了相应的XML映射和Java代码示例。
81 0
|
6月前
|
缓存 Java 数据库连接
我们后端程序员不是操作MyBatis的CRUD Boy
大家好,我是南哥。一个对Java程序员进阶成长颇有研究的人,今天我们接着新的一篇Java进阶指南。为啥都戏称后端是CRUD Boy?难道就因为天天怼着数据库CRUD吗?要我说,是这个岗位的位置要的就是你CRUD,你不得不CRUD。哪有公司天天能给你搭建高并发、高可用、大数据框架的活呢,一条业务线总要成长吧,慢慢成熟了就要装修工来缝缝补补、美化美化,也就是CRUD的活。不能妄自菲薄CRUD Boy,我们是后端工程师。今天来指南下操作数据库之MyBatis框架。
130 3
我们后端程序员不是操作MyBatis的CRUD Boy
|
5月前
|
SQL 缓存 Java
使用MyBatis优化Java持久层操作
使用MyBatis优化Java持久层操作