浅析使用JDBC操作MySQL需要添加Class.forName("com.mysql.jdbc.Driver")

作者:宁愿呢 时间:2024-01-21 23:08:48 

引言

如果熟悉使用JDBC来连接数据库的同学一定很清楚连接数据库的代码中一定会有依据Class.forName


("com.mysql.jdbc.Driver");
 public static Connection getConnection() throws ClassNotFoundException, SQLException {
   if(connection == null){
     Class.forName("com.mysql.jdbc.Driver");
     connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxxxx");
   }
   return connection;
 }

之前没有想过为什么需要有这么一个语句,都是按照文档直接这么做的,在这篇文章中我来试着解释这么做的原因。

类加载机制

在这之前我们先来说下Java中的类加载机制。

在Java中如果想要使用一个类,则必须要求该类已经被加载到Jvm中,加载的过程实际上就是通过类的全限定名来获取定义该类二进制字节流,然后将这个字节流所表示的静态存储结构转换为方法去的动态运行时数据结构。同时在在内存中实例化一个java.lang.Class对象,作为方法区中该类的数据访问入口(供我们使用)。

而会触发类加载的会有如下几种情况(引用自<<深入理解Java虚拟机>>):

1.遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令的最常见的Java代码场景是:使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。

2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

3.当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

4.当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。

Class.forName

在Java官方文档中对Class.forName的解释为在运行时动态的加载一个类,返回值为生成的Class对象。

那么很明显在jdbc中使用Class.forName("com.mysql.jdbc.Driver");仅仅就是将com.mysql.jdbc.Driver类加载到Jvm中了,这个原因大多数人应该都知道。

但是我们要知道Class.forName貌似只是对类进行了加载,我们甚至都没有对返回的Class对象做任何操作,那么我们为什么后面就可以直接用了呢?

首先看Class.forName调用了native方法forName0(...);


@CallerSensitive
public static Class<?> forName(String className)
     throws ClassNotFoundException {
 Class<?> caller = Reflection.getCallerClass();
 return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

private static native Class<?> forName0(String name, boolean initialize,ClassLoader loader,Class<?> caller);

要注意forName0中有一个关键的参数boolean initialize,;该参数用来标识在将该类加载后是否进行初始化操作。可以看到代码中是true,就表示会进行初始化操作。

初始化过程实际上就是对变量赋值(不是赋初值,不会调用构造函数)的过程。包含所有类变量的赋值以及静态代码语句块的执行代码,包括对父类的初始化。

再看com.mysql.jdbc.Driver驱动类:


public class Driver extends NonRegisteringDriver implements java.sql.Driver {
 public Driver() throws SQLException {
 }

static {
   try {
     DriverManager.registerDriver(new Driver());
   } catch (SQLException var1) {
     throw new RuntimeException("Can't register driver!");
   }
 }
}

该类中定义了一个静态代码块,静态代码快中创建了一个驱动类实例注册给了DriverManager,而静态代码块的内容会在初始化的过程中执行,所以才能通过DriverManager.getConnection直接获取一个连接。

其他加载类方法

我们需要明白的是在Java中并不是只有通过Class.forName()才能显示的加载类。那么为什么不使用其他的加载方法而偏偏选择Class.forName()呢?

ClassLoader.getSystemClassLoader().loadClass()

通过类加载器也可以将一个类加载到Jvm中。通过ClassLoader.getSystemClassLoader().loadClass("com.mysql.jdbc.Driver");也可以加载驱动类。

但是如果我们深入看下loadClass的实现:


public Class<?> loadClass(String name) throws ClassNotFoundException {
 return loadClass(name, false);
}

protected Class<?> loadClass(String name, boolean resolve);

可以看到其调用了一个重载的方法,该方法也有一个boolean类型的变量boolean resolve,调用时默认为false。该参数用于标识是否对加载后的类进行链接操作,如果不进行连接操作则不会有初始化的操作。

所以如果使用这种加载类方式的话理论上来说是没发使用该驱动类的。

new关键字

也可以使用new关键字进行加载操作,在使用new关键字时会查看该类是否已经被加载,如果没有被加载的话则会进行加载操作。所以我们的类中也可以这样写:


public static Connection getConnection() throws ClassNotFoundException, SQLException {
 if(connection == null){
   new Driver();//会自动调用静态代码块
   connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxx");
 }
 return connection;
}

但是实际上因为在驱动类的静态代码快中实际上已经有了实例化对象并注册到DriverMananger中的操作。所以这里根本就没有在实例化一个对象的过程。使用Class.forName即可,这也算是一个优化的过程吧。

可以不使用Class.forName("com.mysql.jdbc.Driver")

在测试的过程中发现即使不显示的使用Class.forName("com.mysql.jdbc.Driver")也能够连接到数据库,一时间觉得很奇怪。

深入跟踪代码后发现实际上只要我们引入了mysql的驱动包,那么在使用时会根据驱动包下提供的配置文件默认的创建一个类。

浅析使用JDBC操作MySQL需要添加Class.forName("com.mysql.jdbc.Driver")

所以实际上只要引入了该驱动包,那么使用jdbc是可以直接通过DriverManage来获取连接。


public static Connection getConnection() SQLException {
 return DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxxxx");
}

总结

以上所述是小编给大家介绍的为什么使用JDBC操作MySQL需要添加Class.forName("com.mysql.jdbc.Driver") 网站的支持!

来源:https://www.cnblogs.com/liyus/p/10634554.html

标签:jdbc,mysql
0
投稿

猜你喜欢

  • python音频处理用到的操作的示例代码

    2021-05-11 22:05:19
  • python 图像判断,清晰度(明暗),彩色与黑白实例

    2023-09-04 12:58:00
  • 如何让页面在打开时自动刷新一次让图片全部显示

    2024-04-17 10:10:44
  • mysql中find_in_set()函数的使用及in()用法详解

    2024-01-25 18:32:38
  • 在vue-cli脚手架中配置一个vue-router前端路由

    2024-05-28 15:59:13
  • golang方法中receiver为指针与不为指针的区别详析

    2024-04-25 15:06:52
  • Pyinstaller打包文件太大的解决方案

    2022-01-20 22:19:24
  • Mysql实现简易版搜索引擎的示例代码

    2024-01-28 10:42:32
  • JS实现合并json对象的方法

    2023-08-29 15:09:30
  • 5个充满想象力的Web调色板

    2008-08-02 12:55:00
  • PL/SQL number型数据

    2009-02-26 10:59:00
  • 得到自增列的下一个会插入的id

    2024-01-20 17:32:48
  • 用Python制作一个文件加密器

    2023-01-16 02:41:05
  • Python ArcPy实现批量计算多时相遥感影像的各项元平均值

    2022-06-04 14:45:51
  • Python中Parser的超详细用法实例

    2022-05-02 10:16:30
  • python使用两种发邮件的方式smtp和outlook示例

    2021-02-12 13:31:54
  • 从基础开始建立一个JS代码库第1/2页

    2024-04-16 10:40:59
  • PHP获取网页标题的3种实现方法代码实例

    2024-05-03 15:51:06
  • SPSS连接mysql数据库的超详细操作教程

    2024-01-21 13:49:25
  • php json_encode与json_decode详解及实例

    2023-07-04 22:46:27
  • asp之家 网络编程 m.aspxhome.com