MySQL Jdbc 驱动应用和源码解析

217 阅读2分钟

背景

了解MySQL jdbc connector java 和 MySQL 客户端建立连接过程中的协议和网络交互步骤。

概要

本次主要会从MySQL JDBC驱动的常规使用出发,然后介绍MySQL jdbc如何作为业务系统和MySQL数据库服务器之间的沟通媒介,来实现诸如连接建立、登录鉴权、查询和结果处理等基本操作的。具体内容会分如下几个部分。

准备工作

首先是准备工作,包括数据库服务器搭建,抓包工具安装和演示样例代码编写等。其次是介绍具体的连接创建,网络交互等过程。

  • wireshark 用来进行抓包分析协议和网络过程;
  • Idea + Java 写一个简单的样例来配合进行jdbc的解析;
  • 一个运行的MySQL服务,本地使用了mysql 5.7.35,通过docker安装;
  • Mysql jdbc 驱动源码,使用maven可以直接获取,这里版本使用了5.1.48,不同版本会有所差异;
<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<version>5.1.48</version>

</dependency>

第一部分 初试JDBC

package com.demo.all.db;

import org.junit.After;

import org.junit.Before;

import org.junit.Test;

import java.sql.*;

public class JdbcTest {

Connection connection;

@Before

public void init() throws Exception {

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

String url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&profileSQL=true";

String user = "root";

String pass = "pass";

connection = DriverManager.*getConnection*(url, user, pass);

}

@Test

public void testConnection() throws SQLException {

String sql = "select 1";

Statement stmt = connection.createStatement();

ResultSet rs = stmt.executeQuery(sql);

while (rs.next()) {

System.*out*.println(rs.getString(1));

}

stmt.close();

}

@After

public void destroy() throws SQLException {

if (null != connection) {

connection.close();

}

}

}

第二部分 运行机制

  1. 获取参数

  2. 建立连接

  3. 执行握手登录

TCP三次握手建立连接

image.png

Greeting

image.png

Login:

image.png

Login OK:

image.png

Jdbc 获取MySQL服务端参数:

image.png

参数详情:

image.png

/* mysql-connector-java-5.1.48 ( Revision: 29734982609c32d3ab7e5cac2e6acee69ff6b4aa ) */SELECT @@session.auto_increment_increment AS auto_increment_increment, @@character_set_client AS character_set_client, @@character_set_connection AS character_set_connection, @@character_set_results AS character_set_results, @@character_set_server AS character_set_server, @@collation_server AS collation_server, @@collation_connection AS collation_connection, @@init_connect AS init_connect, @@interactive_timeout AS interactive_timeout, @@license AS license, @@lower_case_table_names AS lower_case_table_names, @@max_allowed_packet AS max_allowed_packet, @@net_buffer_length AS net_buffer_length, @@net_write_timeout AS net_write_timeout, @@performance_schema AS performance_schema, @@query_cache_size AS query_cache_size, @@query_cache_type AS query_cache_type, @@sql_mode AS sql_mode, @@system_time_zone AS system_time_zone, @@time_zone AS time_zone, @@transaction_isolation AS transaction_isolation, @@wait_timeout AS wait_timeout;

参数结果:

image.png

调整参数,典型的如characterEncoding,调整后

image.png

一次自定义查询

image.png

对应查询代码

image.png

Select 1对应的返回4个MySQL包

image.png

结束连接和TCP连接断开

image.png

第三部分 核心类

MySQLIO的一些配置

image.png

握手登录

image.png

参数校对和版本兼容

image.png

账号密码验证

image.png

给MySQL发包

image.png

第四部分 常见数据库连接池

Hikari,Dbcp,c3p0

第五部分 冷知识

  • jdbc Ping包

已知在jdbc驱动中会将/* ping */开头的SQL转成ping包,可以减少返回,简化连接验证。