点击下方“IT牧场”,选择“设为星标”

之前,我给大家分享给很多MyBatis源码分析的一系列文章。今天,就自己的感受来做一个整体的总结。

众所周知,MyBatis是对JDBC进行封装而成的产品,所以,聊MyBatis源码之前我们得先了解JDBC

JDBC

JDBC案例:

public class JdbcDemo {public static final String URL = "jdbc:mysql://localhost:3306/mblog";public static final String USER = "root";public static final String PASSWORD = "123456";public static void main(String[] args) throws Exception { Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection(URL, USER, PASSWORD); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT id, name, age FROM m_user where id =1"); while(rs.next()){System.out.println("name: "+rs.getString("name")+" 年龄:"+rs.getInt("age"));}}
}

说明:

数据库驱动:

Class.forName("com.mysql.jdbc.Driver");

获取连接:

Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);

创建Statement或者PreparedStatement对象:

Statement stmt = conn.createStatement();

执行sql数据库查询:

ResultSet rs = stmt.executeQuery("SELECT id, name, age FROM m_user where id =1");

解析结果集:

System.out.println("name: "+rs.getString("name")+" 年龄:"+rs.getInt("age"));

在使用的时候,业务处理完成后记得关闭相关资源

使用过JDCB的朋友都知道,JDBC如果用到我们项目中基本上都会存在以下几个问题:

传统JDBC的问题

  • 创建数据库的连接存在大量的硬编码,

  • 执行statement时存在硬编码.

  • 频繁的开启和关闭数据库连接,会严重影响数据库的性能,浪费数据库的资源.

  • 存在大量的重复性编码

针对上面这些问题,于是一大堆持久化框架应运而生。

持久化框

做持久层的框架有很多,有orm系和utils系列。

  • orm系列的代表有:hibernateeclipseLinktopLink

  • utils系列的代表有:MyBatisdbUtilsjdbcTemplate等;

下面对于这些框架做个简单概述:

至于 jpa,它只是一个规范标准,并非具体框架,不等同于 spring-data-jpa;同时 spring-data-jpa 也不是 jpa 的具体实现,它只是 jpa 规范标准的进一步封装。hibernate 是 jpa 最为常见的实现框架,当然其他还有 eclipseLink,topLink。

MyBatis 的特点是在对 SQL 优化时,复杂 SQL 的优化可控性高,框架内部调用层次简单,除了部分可以自动生成代码,还会有很多 SQL 需要自行编码。spring-data-jpa(hibernate) 的特点是在开发过程中,脱离 SQL 编码开发,当然也支持本地SQL来查询,框架内部调用层次复杂。以上就可以根据实际的业务进度和业务支撑情况做出选择了。

其实可以在一个项目在同时支持 MyBatis 和 spring-data-jpa,复杂SQL走 mybatis,常用SQL走 spring-data-jpa。

鉴于前实际开发中使用数量,我们选择MyBatis 进行分析。

mybatis

新加入开发的朋友,估计不知道MyBatis 的前身,在2010年之前,不交MyBatis ,叫ibatis

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录 。

特点

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。

  • 灵活:MyBatis 不会对应用程序或者数据库的现有设计强加任何影响。sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。

  • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。

  • 提供映射标签,支持对象与数据库的orm字段关系映射

  • 提供对象关系映射标签,支持对象关系组建维护

  • 提供xml标签,支持编写动态sql。

案例

需要来源两个jar包:MyBatis的jar包和MySQL数据库连接jar包。

<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>x.x.x</version>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version>
</dependency>

创建一个表t_user(数据库也是肯定要自己创建的哈)

CREATE TABLE `t_user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`age` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

插入一条数据:

INSERT INTO `t_user` VALUES ('1', 'tian', '19', '1');

创建该数据库表的实体类:

public class User {private Integer id;private String name;private Integer age;//set get
}

创建mapper配置文件:UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tian.mapper.UserMapper"><select id="selectUserById" resultType="com.tian.domain.User">select * from t_user where id = #{id}</select>
</mapper>

创建mapper接口:UserMapper.java

import com.tian.domain.User;public interface UserMapper {User selectUserById(Integer id);
}

MyBatis 整体配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mblog?useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;useSSL=false&amp;serverTimezone=UTC"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><mappers><mapper resource="mappers/UserMapper.xml"/></mappers>
</configuration>

上面这些就是我们使用MyBatis基本开发代码。

下面我们来写一个测试类:

import com.tian.domain.User;
import com.tian.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.InputStream;public class MybatisApplication {public static void main(String[] args) {String resource = "mybatis-config.xml";InputStream inputStream = null;SqlSession sqlSession =null;try {//读取配置文件inputStream = Resources.getResourceAsStream(resource);//创建SqlSession工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//创建sql操作会话sqlSession = sqlSessionFactory.openSession();UserMapper userMapper=sqlSession.getMapper(UserMapper.class);//获取数据并解析成User对象User user = userMapper.selectUserById(1);//输出System.out.println(user);} catch (Exception e) {e.printStackTrace();}finally {//关闭相关资源try {inputStream.close();} catch (IOException e) {e.printStackTrace();}sqlSession.close();}}}

测试结果:

User{id=1, name='tian', age=19}

如上面的代码所示,SqlSession是MyBatis中提供的与数据库交互的接口,SqlSession实例通过工厂模式创建。

为了创建SqlSession对象,首先需要创建SqlSessionFactory对象,而SqlSessionFactory对象的创建依赖于SqlSessionFactoryBuilder类,该类提供了一系列重载的build()方法,我们需要以主配置文件的输入流作为参数调用SqlSessionFactoryBuilder对象的bulid()方法,该方法返回一个SqlSessionFactory对象。

有了SqlSessionFactory对象之后,调用SqlSessionFactory对象的openSession()方法即可获取一个与数据库建立连接的SqlSession实例。

前面我们定义了UserMapper接口,这里需要调用SqlSessiongetMapper()方法创建一个动态代理对象,然后调用UserMapper代理实例的方法即可完成与数据库的交互。

针对上面这个案例,我们来梳理一下MyBatis的整体执行流程和核心组件。

MyBatis 核心组件

MyBatis 执行流程


Configuration

用于描述MyBatis的主配置信息,其他组件需要获取配置信息时,直接通过Configuration对象获取。除此之外,MyBatis在应用启动时,将Mapper配置信息、类型别名、TypeHandler等注册到Configuration组件中,其他组件需要这些信息时,也可以从Configuration对象中获取。

MappedStatement

MappedStatement用于描述Mapper中的SQL配置信息,是对Mapper XML配置文件中<select|update|delete|insert>等标签或者@Select/@Update等注解配置信息的封装。

SqlSession

SqlSession是MyBatis提供的面向用户的API,表示和数据库交互时的会话对象,用于完成数据库的增删改查功能。SqlSession是Executor组件的外观,目的是对外提供易于理解和使用的数据库操作接口。

Executor

Executor是MyBatis的SQL执行器,MyBatis中对数据库所有的增删改查操作都是由Executor组件完成的。

StatementHandler

StatementHandler封装了对JDBC Statement对象的操作,比如为Statement对象设置参数,调用Statement接口提供的方法与数据库交互,等等。

ParameterHandler

MyBatis框架使用的Statement类型为CallableStatementPreparedStatement时,ParameterHandler用于为Statement对象参数占位符设置值。

ResultSetHandler

ResultSetHandler封装了对JDBC中的ResultSet对象操作,当执行SQL类型为SELECT语句时,ResultSetHandler用于将查询结果转换成Java对象。

TypeHandler

TypeHandler是MyBatis中的类型处理器,用于处理Java类型与JDBC类型之间的映射。它的作用主要体现在能够根据Java类型调用PreparedStatementCallableStatement对象对应的setXXX()方法为Statement对象设置值,而且能够根据Java类型调用ResultSet对象对应的getXXX()获取SQL执行结果。

使用JDBC API开发应用程序,其中一个比较烦琐的环节是处理JDBC类型与Java类型之间的转换。涉及Java类型和JDBC类型转换的两种情况如下:

  • PreparedStatement对象为参数占位符设置值时,需要调用PreparedStatement接口中提供的一系列的setXXX()方法,将Java类型转换为对应的JDBC类型并为参数占位符赋值。

  • 执行SQL语句获取ResultSet对象后,需要调用ResultSet对象的getXXX()方法获取字段值,此时会将JDBC类型转换为Java类型。

MyBatis提供的TypeHandler及与Java类型和JDBC类型之间的对应关系:

小结

我们使用到了SqlSession组件,它是用户层面的API。实际上SqlSession是Executor组件的外观,目的是为用户提供更友好的数据库操作接口,这是设计模式中外观模式的典型应用。

真正执行SQL操作的是Executor组件,Executor可以理解为SQL执行器,它会使用StatementHandler组件对JDBC的Statement对象进行操作。

当Statement类型为CallableStatementPreparedStatement时,会通过ParameterHandler组件为参数占位符赋值。ParameterHandler组件中会根据Java类型找到对应的TypeHandler对象,TypeHandler中会通过Statement对象提供的setXXX()方法(例如setString()方法)为Statement对象中的参数占位符设置值。

StatementHandler组件使用JDBC中的Statement对象与数据库完成交互后,当SQL语句类型为SELECT时,MyBatis通过ResultSetHandler组件从Statement对象中获取ResultSet对象,然后将ResultSet对象转换为Java对象。

推荐:教小师妹快速入门Mybatis,看这篇就够了

高级技能

设计模式

在MyBatis 中大量的使用了设计模式,在MyBatis 我们可以学到一下几种设计模式:

  • 工厂模式

  • 模板方法模式

  • 代理模式

  • 建造者模式

  • 单例模式

  • 适配模式

  • 装饰器模式

  • 责任链模式

  • ....

推荐:面试官:Mybatis里的设计模式有哪些?

缓存

在 Web 应用中,缓存是必不可少的组件。通常我们都会用 Redis 或 memcached 等缓存中间件,拦截大量奔向数据库的请求,减轻数据库压力。作为一个重要的组件,MyBatis 自然也在内部提供了相应的支持。通过在框架层面增加缓存功能,可减轻数据库的压力,同时又可以提升查询速度,可谓一举两得。

MyBatis 缓存结构由一级缓存二级缓存构成,这两级缓存均是使用 Cache 接口的实现类。因此,在接下里的章节中,我将首先会向大家介绍 Cache 几种实现类的源码,然后再分析一级和二级缓存的实现。

MyBatis一级缓存和二级缓存的使用:MyBatis一级缓存是SqlSession级别的缓存,默认就是开启的,而且无法关闭;二级缓存需要在MyBatis主配置文件中通过设置cacheEnabled参数值来开启。

一级缓存是在Executor中实现的。MyBatis的Executor组件有3种不同的实现,分别为SimpleExecutorReuseExecutorBatchExecutor。这些类都继承自BaseExecutor,在BaseExecutor类的query()方法中,首先从缓存中获取查询结果,如果获取不到,则从数据库中查询结果,然后将查询结果缓存起来。而MyBatis的二级缓存则是通过装饰器模式实现的,当通过cacheEnabled参数开启了二级缓存,MyBatis框架会使用CachingExecutor对SimpleExecutorReuseExecutor或者BatchExecutor进行装饰,当执行查询操作时,对查询结果进行缓存,执行更新操作时则更新二级缓存。本章最后介绍了MyBatis如何整合Redis作为二级缓存。

除此之外,MyBatis还支持EhcacheOSCache等,这种特性并不常用。

推荐:@万字长文 | MyBatis 缓存到底

插件

大多数框架,都支持插件,用户可通过编写插件来自行扩展功能,Mybatis也不例外。

MyBatis提供了扩展机制,能够在执行Mapper时改变SQL的执行行为。这种扩展机制是通过拦截器来实现的,用户自定义的拦截器也被称为MyBatis插件。

MyBatis框架支持对ExecutorParameterHandlerResultSetHandlerStatementHandler四种组件的方法进行拦截。掌握了MyBatis插件的实现原理,然后自己实现一个分页查询插件和慢SQL统计插件,当我们需要的功能MyBatis框架无法满足时,可以考虑通过自定义插件来实现。

经典实现:PageHelper 。

推荐:建议收藏,mybatis插件原理详解

日志

MyBatis针对不同的日志框架提供对Log接口对应的实现,Log接口的实现类下图所示。从实现类可以看出,MyBatis支持7种不同的日志实现,具体如下。

下面对常用几个做一个简单说明:

  • Apache Commons Logging:使用JCL输出日志。

  • Log4j 2:使用Log4j 2框架输入日志。

  • Java Util Logging:使用JDK内置的日志模块输出日志。

  • Log4j:使用Log4j框架输出日志。

  • No Logging:不输出任何日志。

  • SLF4J:使用SLF4J日志门面输出日志。

  • Stdout:将日志输出到标准输出设备(例如控制台)。

MyBatis查找日志框架的顺序为

SLF4J→JCL→Log4j2→Log4j→JUL→No Logging。

如果Classpath下不存在任何日志框架,则使用NoLoggingImpl日志实现类,即不输出任何日志。

动态SQL绑定

动态SQL指的是事先无法预知具体的条件,需要在运行时根据具体的情况动态地生成SQL语句。

在MyBatis中有着丰富的动态SQL标签,比如:<where><if><choose|when|otherwise><foreach>等。

在MyBatis源码中有个SqlSource对象会作为MappedStatement对象的属性保存在MappedStatement对象中。执行Mapper时,会根据传入的参数信息调用SqlSource对象的getBoundSql()方法获取BoundSql对象,这个过程就完成了将SqlNode对象转换为SQL语句的过程。

比如:,#{}占位符会被替换为“?”,然后调用JDBC中PreparedStatement对象的setXXX()方法为参数占位符设置值,而${}占位符则会直接替换为传入的参数文本内容。

推荐:掌握Mybatis动态映射,我可是下了功夫的

总结

本文是对MyBatis源码分析的整体感受,希望对你有点点帮助。

咱们不是为了看源码而看源码,更不是为了装B而看源码,更多是我们从这个源码中学到了什么。比如学到了设计模式是怎么使用的,学会了插件的思想,学会了缓存是怎么使用的等等。

个人觉得学习MyBatis源码有几个好处:

  • 掌握Mybatis整体思想

  • 学到一些核心技能

  • 对于实际工作中排查问题有所帮助

  • 面试还可以吹吹牛

干货分享最近将个人学习笔记整理成册,使用PDF分享。关注我,回复如下代码,即可获得百度盘地址,无套路领取!
•001:《Java并发与高并发解决方案》学习笔记;•002:《深入JVM内核——原理、诊断与优化》学习笔记;•003:《Java面试宝典》•004:《Docker开源书》•005:《Kubernetes开源书》•006:《DDD速成(领域驱动设计速成)》•007:全部•008:加技术群讨论
加个关注不迷路
喜欢就点个"在看"呗^_^

一周学完MyBatis源码,万字总结相关推荐

  1. 十年老架构师神级推荐,MyBatis源码分析,再也不用为源码担忧了

    十年老架构师神级推荐,MyBatis源码分析,再也不用为源码担忧了 前言 MyBatis是一个优秀的持久层ORM框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL 本身,而不需要花 ...

  2. MyBatis 源码分析系列文章导读

    1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章.本篇文章从 MyBatis 是什么(what),为什么要使用(why),以及如何使用(how)等三个角度进行了说 ...

  3. MyBatis 源码分析系列文章导读 1

    1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章.本篇文章从 MyBatis 是什么(what),为什么要使用(why),以及如何使用(how)等三个角度进行了说 ...

  4. MyBatis 源码分析系列文章合集

    1.简介 我从七月份开始阅读MyBatis源码,并在随后的40天内陆续更新了7篇文章.起初,我只是打算通过博客的形式进行分享.但在写作的过程中,发现要分析的代码太多,以至于文章篇幅特别大.在这7篇文章 ...

  5. Mybatis源码阅读(一):Mybatis初始化1.1 解析properties、settings

    *************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如 ...

  6. 【Mybatis源码】源码分析

    [Mybatis源码]源码分析 (一)Mybatis重要组件 [1]四大核心组件 (1)SqlSessionFactoryBuilder (2)SqlSessionFactory (3)SqlSess ...

  7. java毕业设计短视频网站mybatis+源码+调试部署+系统+数据库+lw

    java毕业设计短视频网站mybatis+源码+调试部署+系统+数据库+lw java毕业设计短视频网站mybatis+源码+调试部署+系统+数据库+lw 本源码技术栈: 项目架构:B/S架构 开发语 ...

  8. java毕业设计居民个人健康信息与个人健康服务综合平台mybatis+源码+调试部署+系统+数据库+lw

    java毕业设计居民个人健康信息与个人健康服务综合平台mybatis+源码+调试部署+系统+数据库+lw java毕业设计居民个人健康信息与个人健康服务综合平台mybatis+源码+调试部署+系统+数 ...

  9. 看完Spring源码记不住,是我脑子不太好吗?

    都说大厂面试必问源码,可很多人看完Spring源码记不住,是脑子有问题吗?当然不是!是因为你没有掌握学习源码的技巧. 看完源码的我- 我的朋友"路神"子路和"大魔王&qu ...

最新文章

  1. Response.Redirect() 跳转中的ThreadAbortException
  2. 聚合类新闻client初体验
  3. linux 安装sysstat使用iostat、mpstat、sar、sa
  4. rm -rf ~/.bashrc 的惨痛教训
  5. php curl_init函数用法
  6. java 泛型应用,通用返回类,泛型方法,泛型静态方法
  7. Jquery 图片走马灯效果原理
  8. 高通平台printk输出log到串口
  9. Linux刻录光盘win10认不到,win10系统无法读取DVD和刻录光盘的具体操作步骤
  10. WordPress页面教程【2021】
  11. “海潮效应”侵袭厨电市场,品牌突围时不我待
  12. AUTOSAR I-PDU的理解以及I-PDU的Callout
  13. LWN:Linux audio plugin APIs综述!
  14. java——Java环境搭建:JDK安装、常用命令
  15. 程序员的5个级别,你属于哪一个等级?
  16. 艾宾浩斯遗忘曲线PHP,艾宾浩斯记忆遗忘曲线 复习计划表 网盘下载
  17. 拼多多2021笔试真题集 -- 1. 多多的数字组合
  18. 统计学——数据的分类
  19. 谦逊、踏实的低头做事,每日反思。——送给自己。
  20. 使用.net和jquery实现一对一的网页聊天系统

热门文章

  1. npm常用命令学习(npm install -D,semver版本规范, npm进行版本管理的最佳实践用法)...
  2. 恰当应用计算机提高课堂教学效率,教学多媒体论文,关于计算机辅助英语教学需要增强实效性相关参考文献资料-免费论文范文...
  3. 计算机网络实验教程钱德沛_计算机网络实验
  4. AI面试常见题目整理
  5. 汽车电子常用英文单词
  6. 2020中国科技机器人企业TOP50
  7. 面试求职中遇到的那些问题
  8. (转)Doug Cutting 访谈录 -- 关于搜索引擎的开发
  9. 博客升级_原水_新浪博客
  10. LaTeX 关于缩进的设置取消默认的段落前的首行缩进