MySQL的JDBC驱动源码解析

本文深入解析 MySQL JDBC 驱动的工作原理,涵盖驱动加载、数据库连接、预编译 SQL 执行流程等内容,并通过实测揭示预编译 SQL 的性能影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、背景

        MySQL是一个中小型关系型数据库管理系统,目前我们淘宝也使用的也非常广泛。为了对开发中间DAO持久层的问题能有更深的理解以及最近在使用的phoenix on Hbase的SQL也是实现的JDBC规范,在遇到问题的时候能够有更多的思路,于是研究了一下MySQL_JDBC驱动的源码,大家都知道JDBC是Java访问数据库的一套规范,具体访问数据库的细节有各个数据库厂商自己实现,看驱动实现也有助有我们更好的理解JDBC规范,并且在这过程中也发现了一直以来对于PreparedStatement常识理解上的错误,与大家分享(MySQl版本5.1.39,JDBC驱动版本5.1.7,JDK版本1.6)。  

二、JDBC典型应用
     下面是个最简单的使用JDBC取得数据的应用。主要能分成几个步骤,分别是①加载数据库驱动,②获取数据库连接,③创建PreparedStatement,并且设置参数  ④ 执行查询 ,来分步分析这个过程。基本上每个步骤的源码分析我都画了时序图,如果不想看文字的话,可以对着时序图看。最后我还会分析关于PreparedStatement预编译的话题,有兴趣的同学可以仔细看下。

Java代码  

1. public class PreparedStatement_Select {  

2.     private Connection conn = null;  

3.     private PreparedStatement pstmt = null;  

4.     private ResultSet rs = null;  

5.     private String sql = "SELECT * FROM user WHERE id = ?";

7.     public void selectStudent(int id) {  

8.         try {  

9.             // step1:加载数据库厂商提供的驱动程序

10.            Class.forName(“ com.mysql.jdbc.Driver ”);

11.        } catch (ClassNotFoundException e) {  

12.            e.printStackTrace();  

13.        }

15.        String url = "jdbc:mysql://localhost:3306/studb";  

16.        try {  

17.            // step2:提供数据库连接的URL,通过DriverManager获得数据库的一个连接对象  

18.            conn = DriverManager.getConnection(url, "root""root");  

19.        } catch (SQLException e) {  

20.            e.printStackTrace();  

21.        }

23.        try {  

24.            // step3:创建Statement(SQL的执行环境)

25.            pstmt = conn.prepareStatement(sql);  

26.            pstmt.setInt(1, id);  

28.            // step4: 执行SQL语句  

29.            rs = pstmt.executeQuery();  

31.            // step5: 处理结果  

32.            while (rs.next()) {  

33.                int i = 1;  

34.                System.out.print(学员编号: " + rs.getInt(i++));  

35.                System.out.print(", 学员用户名: " + rs.getString(i++));  

36.                System.out.print(", 学员密码: " + rs.getString(i++));  

37.                System.out.println(", 学员年龄: " + rs.getInt(i++));  

38.            }  

39.        } catch (SQLException e) {  

40.            e.printStackTrace();  

41.        } finally {  

42.            // step6: 关闭数据库连接  

43.            DbClose.close(rs, pstmt, conn);  

44.        }  

45.    }  

46.}  

三、JDBC驱动源码解析

      Java数据库连接(JDBC)由一组用 Java 编程语言编写的类和接口组成。JDBC 为工具/数据库开发人员提供了一个标准的 API,使他们能够用纯Java API 来编写数据库应用程序。说白了一套Java访问数据库的统一规范,如下图,具体与数据库交互的还是由驱动实现,JDBC规范之于驱动的关系,也类似于Servlet规范与Servlet容器(Tomcat)的关系,本质就是一套接口和一套实现的关系。如下类图所示,我们平时开发JDBC时熟悉的Connection接口在Mysql驱动中的实现类是com.mysql.jdbc.JDBC4Connection类,PreparedStatement接口在Mysql驱动中的实现类是com.mysql.jdbc.JDBC4Connection, ResultSet接口在Mysql驱动中的实现类是 com.mysql.jdbc.JDBC4ResultSet,下面的源码解析也是通过这几个类展开。


1:加载数据库厂商提供的驱动程序

       首先我们通过Class.forName("com.mysql.jdbc.Driver")来加载mysql的jdbc驱动。 Mysql的com.mysql.jdbc.Driver类实现了java.sql.Driver接口,任何数据库提供商的驱动类都必须实现这个接口。在DriverManager类中使用的都是接口Driver类型的驱动,也就是说驱动的使用不依赖于具体的实现,这无疑给我们的使用带来很大的方便。如果需要换用其他的数据库的话,只需要把Class.forName()中的参数换掉就可以了,可以说是非常方便的,com.mysql.jdbc.Driver类也是驱动实现JDBC规范的第一步。

Java代码  

1.  public class Driver extends NonRegisteringDriver implements java.sql.Driver {  

2.      static {  

3.          try { 

4.              //DriverManager中注册自身驱动

5.              java.sql.DriverManager.registerDriver(new Driver());  

6.          } catch (SQLException E) {  

7.              throw new RuntimeException("Can't register driver!");  

8.          }  

9.      }  

10.     public Driver() throws SQLException {  

11.     }  

12.

      在com.mysql.jdbc.Driver类的静态初始化块中会向java.sql.DriverManager注册它自己 ,注册驱动首先就是初始化,然后把驱动的信息封装一下放进一个叫做DriverInfo的驱动信息类中,最后放入一个驱动的集合中, 到此Mysql的驱动类com.mysql.jdbc.Driver也就已经注册到DriverManager中了。

Java代码  

1.  public static synchronized void registerDriver(java.sql.Driver driver)  throws SQLException {  

2.  if (!initialized) {  

3.      initialize();  

4.  }  

6.  DriverInfo di = new DriverInfo();  

8.  //driver的信息封装一下,组成一个DriverInfo对象  

9.  di.driver = driver;  

10. di.driverClass = driver.getClass();  

11. di.driverClassName = di.driverClass.getName();  

13. writeDrivers.addElement(di);   

14. println("registerDriver: " + di);  

16. readDrivers = (java.util.Vector) writeDrivers.clone();  

17. }  

 注册驱动的具体过程序列图如下:


2.获取数据库连接

      数据库连接的本质其实就是客户端维持了一个和远程MySQL服务器的一个TCP长连接,并且在此连接上维护了一些信息。

       通过 DriverManager.getConnection(url, "root", "root")获取数据库连接对象时,由于之前已经在 DriverManager中注册了驱动类 ,所有会找到那个驱动类来连接数据库com.mysql.jdbc.Driver.connect

Java代码

1.     private static Connection getConnection(  

2.  String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {  

3.  java.util.Vector drivers = null;  

5.  if (!initialized) {  

6.      initialize();  

7.  }  

8.  //取得连接使用的driverreadDrivers中取  

9.  synchronized (DriverManager.class){   

10.     drivers = readDrivers;    

11. }  

13. SQLException reason = null;  

14. for (int i = 0; i < drivers.size(); i++) {  

15.     DriverInfo di = (DriverInfo)drivers.elementAt(i);  

17.     if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {  

18.     continue;  

19.     }  

20.     try {  

21.     // 找到可供使用的驱动,连接数据库server  

22.     Connection result = di.driver.connect(url, info);  

23.     if (result != null) {  

24.         return (result);  

25.     }  

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值