a. 背景

很多时候,在写Java原生代码连接MySQL的时候,我们总能遇到一句神奇的代码行Class.forName("com.mysql.cj.jdbc.Driver");,但这么多年了,我倒其实也不是很清楚它的背后起的是什么作用,如果让我猜,或许是建立一个DatabaseConnection的时候需要使用到对应Driver类中的某些参数or配置信息,而这又依托于这个类已经加载进Java内存空间中,所以通过Class.forName()的方式进行预加载,不晓得我猜的对不对(我要开始Google了,咱今天就要把它搞透

b. Class.forName的背后

image-20221202143754685

以上是Class.forName的源码,API DOC表明来这个方法是用于将指定路径下的类进行初始化(执行类的静态变量初始化 & 静态方法块),并返回类对象,简单地理解,可以把这个过程理解成是注册在了Java的内存空间内,下次再需要到用这个类的静态资源时,可以直接使用!底层也使用到了Java的反射机制来获取是哪个类调用的这个方法,并使用调用这个方法的类的类加载器(ClassLoader)来加载这个目标类

c. com.mysql.cj.jdbc.Driver

如果使用的mysql-connector-java5.x及其以下版本则MySQL的驱动类为com.mysql.jdbc.Driver

如果使用的mysql-connector-java6.0以上版本则MySQL的驱动类为com.mysql.jdbc.Driver

Java SQL框架支持多个数据库驱动器,每一个不同的数据库都应该有自己的驱动类,而DriverManager会尝试加载所能加载到的驱动器用于建立连接请求(也就是Connection),而这个连接着是通过不同的Driver驱动类建立得到,当一个驱动类被加载时,它会创建一个自己的单例并且把自己注册到DriverManager中,意味着使用者也可以通过Class.forName的方式手动做加载,而com.mysql.cj.jdbc.Driver则是MySQL的驱动器

而手动Class.forName("com.mysql.cj.jdbc.Driver");也如开篇所说,主要做的事情是将Driver类加载至Java内存中,以便后续使用,Driver在加载后主要是把自己注册到DriverManager中,如下所示

image-20221202230023368

然而这种手动加载的方式只有在JDBC 4.0前需要,在此后版本的DriverManager中已经实现了主动加载机制,在拿到JDBC URL后会由DriverManager主动load对应的驱动器,相关源码可查阅DriverManager.ensureDriversInitialized()方法

d. 总结

  • 最新版本(JDBC 4.0以上 & Java 6.0起)的JDBC已经不再需要手动做Driver的注册
  • 现有的资料中,大部分示范代码都带有Class.forName("com.mysql.cj.jdbc.Driver");,主要是大量的copy-paste导致,对代码本身无任何影响,唯二的好处可能是当未存在对应驱动类时,会直接抛出对应异常,同时能够兼容旧版本的代码
  • mysql-connector-java5.x及其以下版本则MySQL的驱动类为com.mysql.jdbc.Driver
  • mysql-connector-java6.0以上版本则MySQL的驱动类为com.mysql.jdbc.Driver

e. 相关文章