• JDBC在getConnection之前为什么要调用Class.forName(转)


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

    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

  • 相关阅读:
    postgresql string转decimal后进行排序
    postgresql 自增长ID跳过问题
    携程apollo配置中心服务端如何感知配置更新?
    MATLAB绘制B样条曲线
    BP神经网络
    三次B样条曲线拟合算法
    淘淘IDEA Mavne POM基本配置文件
    slf4j日志的简单用法
    idea测试web连接mysql数据库
    虚拟机如何设置外网ip
  • 原文地址:https://www.cnblogs.com/softidea/p/5174113.html
Copyright © 2020-2023  润新知