获取一个数据库连接的通用模板如下:

String driver = "oracle.jdbc.OracleDriver";
String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
String user = "scott";
String password = "ticmy";
Class.forName(driver);
Connection conn = DriverManager.getConnection(url, user, password);

里面有个Class.forName(driver),这句话有什么作用?将驱动类load到内存?如果没有这句会怎么样?运行发现,如果去掉这一句会有以下异常:
java.sql.SQLException: No suitable driver found for xxx….

在解释具体原因之前先简单看下Class.forName做了什么。

假设一个类以前从来没有被装进内存过,Class.forName(String className)这个方法会做以下几件事情:
1、装载。将字节码读入内存,并产生一个与之对应的java.lang.Class类对象
2、连接。这一步会验证字节码,为static变量分配内存,并赋默认值(0或null),并可选的解析符号引用(这里不理解没关系)
3、初始化。为类的static变量赋初始值,假如有static int a = 1;这个将a赋值为1的操作就是这个时候做的。除此之外,还要调用类的static块。(这一步是要点)

Class.forName(String className)方法会将这三步都做掉,如下面的例子:

package com.ticmy.oracle;
 
public class TestClinit {
    public static void main(String[] args) throws Exception {
        Class.forName("com.ticmy.oracle.ABC");
    }
}
class ABC {
    private static int a = getNum();
    static {
        System.out.println("this is static block");
    }
    public static int getNum() {
        System.out.println("getNum");
        return 1;
    }
}

程序的运行结果是:
getNum
this is static block

那么,Class.forName(driver)这个driver类里有没有什么static块呢?去探究一下。例子用的是Oracle,反编译下oracle.jdbc.OracleDriver,发现其继承了oracle.jdbc.driver.OracleDriver,那么继续看这个oracle.jdbc.driver.OracleDriver,确实有个static块,里面有这样的代码:

static {
    Timestamp localTimestamp = Timestamp.valueOf("2000-01-01 00:00:00.0");
    try {
      if (defaultDriver == null) {
        defaultDriver = new OracleDriver();
        DriverManager.registerDriver(defaultDriver);
      }
    } catch (RuntimeException localRuntimeException) {
    } catch (SQLException localSQLException){}
    _Copyright_2004_Oracle_All_Rights_Reserved_ = null;
}

再看看mysql吧:com.mysql.jdbc.Driver:
同样发现了static块,里面代码如下:

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

再看一个db2:com.ibm.db2.jcc.DB2Driver:
也发现了static块:

static {
    if (o.Nb != null) {
      exceptionsOnLoadDriver__ = dg.a(o.Nb, exceptionsOnLoadDriver__);
    }
 
    try {
      registeredDriver__ = new DB2Driver();
      DriverManager.registerDriver(registeredDriver__);
    }
    catch (SQLException localSQLException) {
      exceptionsOnLoadDriver__ = new SqlException(null,
      "Error occurred while trying to register Jcc driver with JDBC 1 Driver Manager");
      exceptionsOnLoadDriver__.setNextException(localSQLException);
    }
}

无一例外地,发现里面都有DriverManager.registerDriver(driver)的调用。那么是不是可以将开头的例子中的Class.forName换成DriverManager.registerDriver呢?

String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
String user = "scott";
String password = "ticmy";
DriverManager.registerDriver(new OracleDriver());
Connection conn = DriverManager.getConnection(url, user, password);
System.out.println(conn);
conn.close();

经过测试发现OK。现在,已经知道Class.forName(driver)的根本目的就是为了调用DriverManager.registerDriver。

Class.forName还有个重载的方法:Class.forName(String name, boolean initialize, ClassLoader loader),Class.forName(String className)就等价于Class.forName(className, true, currentLoader),注意中间的参数为true,这个参数的含义就是要不要初始化。如果此参数为true且指定的类以前没有被初始化过,就会去初始化。

另外,jdbc4已经不需要显式的调用Class.forName了,在jdbc4中,调用getConnection的时候DriverManager会自动去加载合适的驱动。
http://www.ticmy.com/?p=249

JDBC在getConnection之前为什么要调用Class.forName(转)的更多相关文章

  1. JDBC对MySQL数据库存储过程的调用

    一.MySQL数据库存储过程: 1.什么是存储过程 存储过程(英文:Stored Procedure)是在大型数据库系统中,为了完成特定功能而编写的一组的SQL语句集.存储过程经编译存储在数据库中,用 ...

  2. JDBC学习2:为什么要写Class.forName("XXX")?

    Class.forName(String name) 接上一篇JDBC.本来这个内容是放在前面的一篇里面的一起的,后来发现越写越多,想想看就算了,还是单独开一篇文章好了,这样也能写得更加详细点. 上一 ...

  3. mysql jdbc性能优化之mybatis/callablestatement调用存储过程mysql jdbc产生不必要的元数据查询(已解决,cpu负载减少20%)

    INFO | jvm 1 | 2016/08/25 15:17:01 | 16-08-25 15:17:01 DEBUG pool-1-thread-371dao.ITaskDao.callProce ...

  4. 调用Class.forName()要抛出异常

    今天学JDBC时,用到下面的程序: package bo; import java.sql.Connection; import java.util.ArrayList; import java.ut ...

  5. 为什么要使用class.forname在DriverManager.getConnection之前

    JDBC在getConnection之前为什么要调用Class.forName 获取一个数据库连接的通用模板如下: String driver = "oracle.jdbc.OracleDr ...

  6. eclipse 连接数据库记录

    两篇很好的文章介绍给大家: Eclipse使用JDBC方式连接SQLServer2016 通过Driver与DriverManager连接数据库 --------------------------- ...

  7. Class.forName和registerDriver的区别

    我们都知道JDBC的代码怎么写,比如以MySQL JDBC为例 //注册JDBC驱动 Class.forName("com.mysql.jdbc.Driver"); //然后就可以 ...

  8. 在Jena框架下基于MySQL数据库实现本体的存取操作

    在Jena框架下基于MySQL数据库实现本体的存取操作 转自:http://blog.csdn.net/jtz_mpp/article/details/6224311 最近在做一个基于本体的管理系统. ...

  9. JDBC调用存储过程

    一. JDBC调用存储过程 (1)使用存储过程SQL编写的程序代码,等一段语句和控制流语句.在创建时被编译成机器代码和存储在数据库中的client转让. 存储过程具有以下优势: 1.所生成的机器代码被 ...

随机推荐

  1. ThinkPHP中的volist标签中使用eq标签出错

    参考地址:http://blog.csdn.net/luquansen/article/details/18310855 源码: <volist id="v" name=&q ...

  2. sql语句中 limi的用法

    SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset 使用查询语句时需要返回前几条或者中间的某几行数据时可以用到limit 例如 ...

  3. UIApplicationsharedApplication的常用使用方法

    下面是这个类的一些功能: 1.设置icon上的数字图标 //设置主界面icon上的数字图标,在2.0中引进, 缺省为0 [UIApplicationsharedApplication].applica ...

  4. 【教你zencart仿站 文章1至6教训 高清1280x900视频下载】[支持手机端]

    [教你zencart仿站 第1至6课 高清晰1280x900视频下载][支持移动端] 经过筹备, 我们的课件最终出来了- 我们 zencart联盟合伙人 项目推出的 在线yy同步演示zencart仿站 ...

  5. php-GD库函数(三)

    <?php //imagefilledellipse — 画一椭圆并填充 /*bool imagefilledellipse ( resource $image , int $cx , int ...

  6. C++ 复制功能

    C++ 复制功能 说C++复制功能,它可能不是很熟悉.类中的拷贝构造函数和赋值操作符.可是其实或许我们一不小心就会忽略编译器所做的一些默认操作.引起晦涩的错误.以下分析几种场景: 一.场景一:所有默认 ...

  7. Custom Media Player in WPF (Part 1)

    First of all I would like to welcome everyone to my new blog and wish you all a happy new year… Thro ...

  8. C++使用函数模板

    函数模板: 函数模板是蓝图或处方功能,编译器使用其发电功能系列中的新成员. 第一次使用时,新的功能是创建.从功能模板生成的函数的实例称为模板或模板的实例.函数模板的开始是keywordtemplate ...

  9. Connecting Docker for Cloud Services using SDN and Network Virtualization

     Abstract The explosive scale of container CPUs needs highly efficient network virtualization Chal ...

  10. ASP.NET MVC源码分析

    MVC4 源码分析(Visual studio 2012/2013) HttpModule中重要的UrlRoutingModule 9:this.OnApplicationPostResolveReq ...