MySQL - 通讯


前言

学习 MySQL 通信编码.

数据类型

MySQL 协议中有两种数据类型:

  1. int
    • 固定长度
    • 长度编码
  2. string
    • 固定长度
    • \0 结尾

数据包

MySQL 通信 Payload

类型名称描述
int<3>Payload 长度声明该数据包有效数据为多少字节
int<1>序列ID数据包ID
string<var>payload数据包内容

例如:

关闭连接 COM_QUIT 的 Payload 为:

01 00 00 00 01 | 长度:    1
               | 序列ID:  0x00
               | payload: 0x01

也就是说, 发送一次数据包, Payload 最长可以为 2 24 − 1 2^{24} - 1 2241, int<3> 表示三个字节用来表示长度.

发送 16MB 数据

那如果说, 我需要发送 2 24 2^{24} 224 bit(16MB) 的数据, 那该如何呢?

答案是:

1: ff ff ff 00 ...
2: 00 00 00 01

上面表示有两次连续请求,
第一次发送 Payload 长度为 2 24 2^{24} 224 bit, 序列 ID 为 00, ... 表示 Payload 数据;
第二次发送 Payload 长度为 0, 表示已没有更多 Payload, 序列 ID 为 01.

序列 ID

每个数据包的序列 ID 都会递增,并且可能会回绕。 它从 0 开始,并在命令阶段开始新命令时重置为 0。

实操

查询数据库, 查看 JDBC 请求和 MySQL server 响应数据.

表结构:

DROP TABLE IF EXISTS users;
CREATE TABLE users
(
    id       BIGINT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id',
    username VARCHAR(64)         NOT NULL DEFAULT 'default' COMMENT '用户名',
    age      TINYINT(3)          NOT NULL DEFAULT 1 COMMENT '年龄',
    PRIMARY KEY (id)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8mb4 COMMENT ='用户表';

INSERT INTO users (username, age) VALUES ('小明', 11);

依赖:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.11</version>
</dependency>

代码:

InputStream resourceAsStream = Thread.currentThread()
        .getContextClassLoader()
        .getResourceAsStream("jdbc.properties");
Properties p = new Properties();
p.load(resourceAsStream);

Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection(URL, p);

Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select * from users");

while (resultSet.next()) {
    int id = resultSet.getInt("id");
    System.out.printf("id: %d%n", id);
    String username = resultSet.getString("username");
    System.out.printf("username: %s%n", username);
    int age = resultSet.getInt("age");
    System.out.printf("age: %d%n", age);
}

resultSet.close();
statement.close();
connection.close();

// id: 1
// username: 小明
// age: 11

交互流程

JDBC Client MySQL Server DriverManager::getConnection TCP 三次握手 1 server 相关信息 2 帐号登录 3 相关配置 4 Statement::executeQuery MySQL Request Query 5 MySQL Response 6 TCP ACK 7 Connection::close MySQL Request Quit 8 TCP 四次挥手 9 JDBC Client MySQL Server

DriverManager::getConnection

Connection

IP功能
192.168.3.1client
192.168.3.28server

红色圈起来的是 client 发起的 TCP 三次握手, 这个我们需要去了解 TCP 协议, 这里就不做过多解释.

黄色就是初始握手, 从服务器发送初始握手数据包开始. 此后, 客户端可以选择使用 SSL 连接请求数据包请求建立 SSL 连接,然后客户端发送握手响应数据包。
服务端初始握手:
服务端信息

蓝色是验证帐号信息, 假设客户端要以用户 U 身份登录,并且该用户帐户使用身份验证方法 M。如果客户端和服务器都使用方法 M 在初始握手中生成身份验证数据,则使用快速身份验证路径。 在这种情况下,握手期间已经开始了第一轮认证。 现在,取决于身份验证方法,可以交换其他身份验证数据,直到服务器拒绝或接受连接为止。
客户端用户登录:
登录

绿色是相关配置, 例如设置自动提交:
autocommit

自此, DriverManager::getConnection 的事就做完了, 接下来就是 Statement::executeQuery 做的事了

Statement::executeQuery

JDBC Client MySQL Server select * from users 1 response 2 TCP ACK 3 JDBC Client MySQL Server

我们先看看请求, 请求类型为 COM_QUERY
select
响应数据 COM_QUERY Response
响应数据

Connection::close

JDBC Client MySQL Server Request Quit 1 TCP 四次挥手 2 JDBC Client MySQL Server

在这我们看看开头关闭连接的数据是不是和实际一样的
Request Quit
MySQL 的操作流程到此就完成了.

资源

Chapter 14 MySQL Client/Server Protocol
MySQL Client/Server Protocol

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值