Pre
如果MyBatis的基础用法还不熟悉,31篇入门博客拿走不谢
戳戳戳 —> https://blog.csdn.net/yangshangwei/category_7205317.html
JDBC的执行过程
MyBatis 半自动的ORM框架 ,归根到底底层还是用的JDBC来访问数据库 , 所以有必要先回顾一下JDBC的执行过程
JDBC Demo
【演示Table 】
【演示Code】
public class JdbcTest { public static final String URL = "jdbc:mysql://127.0.0.1:3306/o2o?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false"; public static final String USERNAME = "root"; public static final String PASSWORD = "root"; private Connection connection; @Before public void init() throws SQLException { // 第一步 获取连接 connection = DriverManager.getConnection(URL, USERNAME, PASSWORD); } @After public void over() throws SQLException { connection.close(); } @Test public void jdbcTest() throws SQLException { // 第二步 预编译 & 设置参数 String sql = "SELECT * FROM tb_area WHERE `area_name`=?"; PreparedStatement sql1 = connection.prepareStatement(sql); sql1.setString(1,"北京"); // 第三步 执行SQL sql1.execute(); // 第四步 获取返回结果 ResultSet resultSet = sql1.getResultSet(); while (resultSet.next()) { System.out.println(resultSet.getString(3)); } resultSet.close(); sql1.close();; } }
【执行结果】
【JDBC执行步骤总结】
无非就是下面几步
- 获取连接
- 预处理SQL ,设置参数等
- 执行SQL
- 获取返回结果
Mybatis既然是JDBC的封装框架, 那自然要处理 预处理这一步 ,所以有必要了解下JDBC中的Statement 接口
JDBC Statement 接口
整体接口和类的关系图如下
这里重点说一下 Statement 接口 ,通过该组件来发送对应的SQL与参数 .
它有三种类型:分别是 Statement,PreparedStatement和CallableStatement 接口, 继承关系如上,
【Statement接口】
- 普通的不带参的查询SQL
- 支持批量更新,批量删除
【PreparedStatement接口】
- 继承自Statement接口
- 可变参数的SQL,编译一次,执行多次,效率高
- 安全,有效防止Sql注入等问题
- 支持批量更新,批量删除
【CallableStatement接口】
- 继承自PreparedStatement接口
- 支持带参数的SQL操作
- 支持调用存储过程,提供了对输出和输入/输出参数(INOUT)的支持
除了常见的接口方法, Statement 中还有2个非常规方法需要关注下,因为后续在MyBatis中源码会有体现。
- addBatch: 批处理操作,将多个SQL合并在一起,最后调用executeBatch 一起发送至数据库执行
- setFetchSize:设置从数据库每次读取的数量单位。该举措是为了防止一次性从数据库加载数据过多,导致内存溢出。(MySQL不支持 ,Oracle支持)
MyBatis执行过程
推荐使用鲁班大叔的源码地图来梳理MyBatis的源码执行过程,更直观易懂 。 ------->戳这里<----------
四大组件
每个组件的作用如下:
接口代理: 简化对MyBatis使用,底层使用动态代理实现
Sql会话: 提供增删改查API, 本身不做业务逻辑的处理,所有处理都会交给执行器Executor。这是一个典型的门面设计模式
执行器: 核心作用是处理SQL请求、事务管理、维护缓存以及批处理等 。执行器在的角色更像是一个管理员,接收SQL请求,然后根据缓存、批处理等逻辑来决定如何执行这个SQL请求,并交给JDBC处理器执行具体SQL
JDBC处理器: 主要具体处理JDBCSQL和参数 。在会话中每调用一次CRUD,JDBC处理器就会生成一个实例与之对应(命中缓存除外)
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
请注意在一次SQL会话过程当中四个组件的实例比值分别是 1:1:1:n
组件之间的关系
一个SQL请求通过会话到达执行器,然后交给对应的JDBC处理器进行处理。
另外所有的组件都不是线程安全的,不能跨线程使用 (currentSql 全局变量 ,线程不安全 )
接下来我们重点看下Executor组件,从源码上剖析该组件的设计思想。
Executor 执行器组件
架构总览
Executor是MyBatis执行者接口 ,执行器的主要功能包括:
- 基本功能:改、查,(增删—>也是改)
- 缓存维护:这里的缓存主要是为一级缓存服务,功能包括创建缓存Key、清理缓存、判断缓存是否存在
- 事务管理:提交、回滚、关闭、批处理刷新
接口继承关系
后面我们重点看下Executor的 三个实现子类。
分别是:SimpleExecutor(简单执行器)、ReuseExecutor(重用执行器)、BatchExecutor(批处理执行器)。