当前位置: 移动技术网 > IT编程>数据库>Mysql > 浅析使用JDBC操作MySQL需要添加Class.forName("com.mysql.jdbc.Driver")

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

2019年07月19日  | 移动技术网IT编程  | 我要评论
引言 如果熟悉使用jdbc来连接数据库的同学一定很清楚连接数据库的代码中一定会有依据class.forname ("com.mysql.jdbc.driver"

引言

如果熟悉使用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是可以直接通过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") ,希望对大家有所帮助

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

  • Ubuntu上Vim安装NERDTree插件的详细操作步骤

    Ubuntu上Vim安装NERDTree插件的详细操作步骤

    nerdtree是vim的文件系统浏览器,使用此插件,用户可以直观地浏览复杂的目录层次结构,快速打开文件以进行读取或编辑,以及执行基本的文件系统操作。nerdt... [阅读全文]
  • MySQL 4种常用的主从复制架构

    MySQL 4种常用的主从复制架构

    一主多从复制架构在主库读取请求压力非常大的场景下,可以通过配置一主多从复制架构实现读写分离,把大量的对实时性要求不是特别高的读请求通过负载均衡分部到多个从库上(... [阅读全文]
  • 浅析MySQL 备份与恢复

    1、简介数据无价,mysql作为一个数据库系统,其备份自然也是非常重要且有必要去做。备份的理由千千万,预防故障,安全需求,回滚,审计,删了又改的需求等等,备份的... [阅读全文]
  • 保障MySQL数据安全的一些建议

    数据是企业核心资产,数据对企业而言是最重要的工作之一。稍有不慎,极有可能发生数据无意泄露,甚至被黑客恶意窃取的风险。每年业界都会传出几起大事件,某知名或不知名的... [阅读全文]
  • MySQL如何快速修改表的表结构

    快速修改mysql某张表的表结构--摘录自《mysql管理之道》alter table 表名 modify 列名 数据类型; 这个命令可以修改表结构此外,也可以... [阅读全文]
  • MySQL 行锁和表锁的含义及区别详解

    一、前言对于行锁和表锁的含义区别,在面试中应该是高频出现的,我们应该对mysql中的锁有一个系统的认识,更详细的需要自行查阅资料,本篇为概括性的总结回答。mys... [阅读全文]
  • MySQL 如何查询当前最新事务ID

    写在前面:在个别时候可能需要查看当前最新的事务 id,以便做一些业务逻辑上的判断(例如利用事务 id 变化以及前后时差,统计每次事务的响应时长等用途)。通常地,... [阅读全文]
  • 如何优雅、安全的关闭MySQL进程

    前言本文分析了 mysqld 进程关闭的过程,以及如何安全、缓和地关闭 mysql 实例,对这个过程不甚清楚的同学可以参考下。关闭过程1、发起 shutdown... [阅读全文]
  • 详解MySQL8.0&#8203; 字典表增强

    详解MySQL8.0&#8203; 字典表增强

    mysql中数据字典是数据库重要的组成部分之一,information_schema首次引入于mysql 5.0,作为一种从正在运行的mysql服务器检索元数据... [阅读全文]
  • 简述MySQL InnoDB存储引擎

    前言:存储引擎是数据库的核心,对于 mysql 来说,存储引擎是以插件的形式运行的。虽然 mysql 支持种类繁多的存储引擎,但最常用的当属 innodb 了,... [阅读全文]
验证码:
移动技术网