导读:最近在研究 Calcite 时发现其使用 Avatica 框架来构建数据库驱动程序,这引起了我一个好奇点,MySQL 的驱动程序底层是采用什么方式与 MySQL 数据库通信的?
基本概念
在深入分析前我们先回顾一些重要的概念
- JDBC:由 Java 语言编写的一组用于规范客户端程序如何访问数据库的应用程序接口。
- JDBC规范与驱动(JDBC drivers)的关系:两者类似于接口和接口的实现类。Java 应用程序通过驱动程序与数据库进行通信。
JDBC 的核心组成:
- DriverManager: 管理JDBC驱动程序的基本服务,使用通信子协议将来自 Java 应用程序的连接请求与适当的数据库驱动程序匹配。这个类里都是静态方法,主要通过调用getConnection 方法获取 Connection对象。
- Driver: 这个接口处理与数据库服务器的通信,每个驱动程序都要实现 Driver 接口。在加载某一 Driver 驱动类时创建其实例并向 DriverManager 注册该实例。
- Connection
- Statement
- ResultSet
- SQLException
具体分析
1、引入 MySQL 驱动 jar 包
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.13</version> </dependency>
2、使用 JDBC 连接数据库的常规步骤
// 注册驱动 Cla(“com.my”); // 创建连接对象 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","root"); Statement stmt = conn.createStatement(); // 获取结果 ResultSet rs = ("select * from table");
3、接下来我们以下面这句代码为入口具体分析 MySQL 驱动程序底层是如何与数据库进行通信
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
4、继续深入 getConnection
private static Connection getConnection( String url, java.u info, Class<?> caller) throws SQLException { //... Connection con = aDriver.driver.connect(url, info); // 关键代码 //.... }
connet() 方法是每个数据库驱动自己的实现的。在 MySQL 驱动程序中 NonRegisteringDriver 类实现了 Driver 接口,其 connet() 实现如下:
public class NonRegisteringDriver implements Driver { //... public Connection connect(String url, Properties info) throws SQLException { try { try { if (!Connec(url)) { return null; } else { ConnectionUrl conStr = Connec(url, info); switc()) { case SINGLE_CONNECTION: // 关键代码,获取一个实例 return Connec()); case LOADBALANCE_CONNECTION: return LoadBalancedConnec((LoadbalanceConnectionUrl)conStr); case FAILOVER_CONNECTION: return FailoverConnec(conStr); case REPLICATION_CONNECTION: return ReplicationConnec((ReplicationConnectionUrl)conStr); default: return null; } } } catch (UnsupportedConnectionStringException var5) { return null; } catch (CJException var6) { throw (UnableToConnectException, Me("NonRegi;, new Object[]{var6.toString()}), var6); } } catch (CJException var7) { throw SQLExce(var7); } } //... }
5、继续深入 getInstance 方法
public static JdbcConnection getInstance(HostInfo hostInfo) throws SQLException { return new ConnectionImpl(hostInfo); }
(关键)ConnectionImpl 构造方法里调用 createNewIO 方法:
// 构造方法 public ConnectionImpl(HostInfo hostInfo) throws SQLException { //... try { // 调用 createNewIO (false); (); NonRegi(this); } catch (SQLException var3) { (var3); throw var3; } catch (Exception var4) { (var4); throw SQLError.createSQLException((Boolean).getValue() ? Me("Connec;) : Me("Connec;, new Object[]{().getHost(), ().getPort()}), "08S01", var4, ()); } }
6、深入 createNewIO 方法
@Override public void createNewIO(boolean isForReconnect) { synchronized (getConnectionMutex()) { try { if (!()) { // 关注点 connectOneTryOnly(isForReconnect); return; } connectWithRetries(isForReconnect); } catch (SQLException ex) { } } } private void connectOneTryOnly(boolean isForReconnect) throws SQLException { Exception connectionNotEstablishedBecause = null; JdbcConnection c = getProxy(); // 这里的 session 是 NativeSession , , , , DriverManager.getLoginTimeout() * 1000, c); ); }
7、深入 方法
这里我们可以看到 Socket 的字眼,跟进来到 NativeSocketConnection 的 connect 方法。
public class NativeSocketConnection extends AbstractSocketConnection implements SocketConnection { public void connect(String hostName, int portNumber, PropertySet propSet, ExceptionInterceptor excInterceptor, Log log, int loginTimeout) { //... = ).getStringValue()); = (Socket).connect, , propSet, loginTimeout); //... } }
这里的 socketFactory 是 StandardSocketFactory,也就是说这里调用的是 StandardSocketFactory 的 connect 方法:
//StandardSocketFactory public <T extends Closeable> T connect(String hostname, int portNumber, PropertySet pset, int loginTimeout) throws IOException { = createSocket(pset); .connect(sockAddr, getRealTimeout(connectTimeout)); } protected Socket createSocket(PropertySet props) { return new Socket(); }
自此就算到底了,结论为:MySQL 驱动其底层是通过 Socket 与 MySQL数据库进行通信的。
总结
JDBC 是由 Java 语言编写的一组用于规范客户端程序如何访问数据库的应用程序接口。MySQL的驱动程序实现了 JDBC 规范并提供了与 MySQL 数据库连接的具体细节,其在ConnectionImp 的构造方法里有个 createNewIO() 方法,最终底层通过 socket 与数据库建立连接。
感谢您的阅读,如果喜欢本文欢迎关注和转发,本头条号将坚持持续分享IT技术知识。对于文章内容有其他想法或意见建议等,欢迎提出共同讨论共同进步。
参考文章