首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164…
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca…
一 .前言
出于好奇 , 这一篇来看一下 MySQL Client 端的调用主流程 , 为后续的 MySQL 系列文档开个头
二 . 创建 Connect
以获取连接为例 , 当获取连接时 , 会通过多种方式调用 Spring 的 DataSourceUtils # getConnection
此时还处在 Spring 的业务体系中. Connect 的流程在启动时创建和运行时调用是两个完全不同的流程 , 先来看一 CreateConnect 的主流程
1 | java复制代码// Step 1 : Connect 的创建入口 |
三 . 运行 SQL 流程
这一节来看一下执行 SQL 时的调用流程
在一个 SQL 的生命周期中 , 主要有2个主要的流程 :
- 流程一 : 基于事务起点的 SET autocommit
- 流程二 : 真正核心的 SQL 执行语句
3.1 事务的入口
Spring 的事务起点是 TransactionAspectSupport , 进入一系列流程后 , 会进入连接池的处理中 , 这里涉及到 SpringTransaction 的流程 , 可以看看这篇文章 基于 Spring 的事务管理, 这里只是简单过一下
- Step 1 : TransactionImpl # begin : 由 Begin 开启事务流程
- Step 2 :ConnectionImpl # setAutoCommit : 开启自动提交流程
- Step 3 : NativeSession # execSQL : 进入 SQL 执行核心流程
1 | java复制代码public void begin() { |
事务会调用setAutoCommit , 其根本也是调用一个execSQL 语句来控制事务
1 | java复制代码this.session.execSQL(null, autoCommitFlag ? "SET autocommit=1" : "SET autocommit=0", -1, null, false, this.nullStatementResultSetFactory, this.database, null, false); |
到了这里会直接调用到 execSQL , 而流程二的普通 SQL 语句 , 会由对应的 executeUpdate / executeQuery /executeInternal 发起流程处理
3.2 普通业务执行流程
- Step 1 : AbstractEntityPersister # insert : 由 Hibernate/JPA 发起的操作流程
- Step 2 : ResultSetReturnImpl # executeUpdate : 执行 Update 语句 (或者 Query -> executeQuery)
- Step 3 : HikariProxyPreparedStatement # executeUpdate : 连接池的中间处理 , 后续可以专门看看
- Step 4 : ClientPreparedStatement # executeUpdate : 由 mysql 驱动接管
- Step 5 : ClientPreparedStatement # executeUpdateInternal :
- Step 5 : ClientPreparedStatement # executeInternal : 由底层方法调用抽象类 , 最终调用 execSQL
1 | java复制代码// 处理 Update 语句 , 核心流程如下 : |
executeInternal 主流程
1 | java复制代码protected <M extends Message> ResultSetInternalMethods executeInternal(int maxRowsToRetrieve, M sendPacket, boolean createStreamingResultSet, |
3.3 业务处理通用流程
看了入口方法, 现在来看一下 execQuery 的具体处理流程 :
1 | java复制代码// C- NativeSession |
在上文调用 sendQueryPacket 发起了SQL 执行操作
1 | java复制代码// C- NativeProtocol |
3.5 发送命令
1 | java复制代码// C- NativeProtocol |
1 | java复制代码// C- NativeProtocol |
C- SimplePacketSender
1 | JAVA复制代码public void send(byte[] packet, int packetLen, byte packetSequence) throws IOException { |
3.6 解析 Result
Step 1 : packetReader.readMessage
这里的 packetReader 主要包含以下几种实现 MultiPacketReader :
1 | JAVA复制代码public NativePacketPayload readMessage(Optional<NativePacketPayload> reuse, NativePacketHeader header) throws IOException { |
checkErrorMessage 判断是否为错误返回
1 | java复制代码public void checkErrorMessage(NativePacketPayload resultPacket) { |
获取最终返回结果
1 | java复制代码public <T extends Resultset> T readAllResults(int maxRows, boolean streamResults, NativePacketPayload resultPacket, boolean isBinaryEncoded, |
总结
东西不多 , 主要是一些主流程代码 , 其中很多环节都比较模糊 , 主要是为了串联整个流程 , 后续小细节会抽空深入的了解一下.
相对于其他的框架代码 , Mysql 的代码看起来很生涩难懂 , 每个主流程间参杂了很多辅助属性 , 如果业务上出现了问题 , 又不确定最终的执行语句 ,可以考虑在 sendCommand 等方法中添加断点
连接池的使用通常在 ResultSetReturnImpl 和 ClientPreparedStatement 之间进行处理 , 后续可以关注一下
本文转载自: 掘金