今天闲来无事,看了看刚学java时候的数据库demo程序;代码再简单不过,相信大家在熟悉不过了 ,无非就是如下(以mysql为例) :
Class.forName( "com.mysql.jdbc.Driver" );
String url = "jdbc:mysql://127.0.0.1/test" ;
String user = "root" ;
String psw = "root" ;
Connection con = DriverManager.getConnection(url,user,psw);
余下了就不写了,写的话估计大家也是味同嚼蜡;
相信刚接触到数据库的朋友也回见过这在普通不过的代码了,因为是初学,所以每个人都小心翼翼的参照教科书上的步骤依葫芦画瓢,也没有人会太关心为什么那么写;还有些人说 不要太关心底层的东西;但今天我一个疑惑在我的大脑里面产生了,那就是Class.forName到底有怎么用,或许有人会说是加载数据库驱动,对那是教科书的说法,我没有说他错,但到底是怎么加载 的呢;我非常疑惑的是class.forName并没有作为任何语句的右值,也就是并没有出现我们编程中的Student s=new Student(); s.say();等常见的形式; 疑惑出现了,就要解答,我从来不习惯于也不迷信于教科书上的讲法,更何况今天有点时间;根据之前写程序的经验class.forName的作用主要有几个方面 一 获得一个类的实例 如Student.class.newInstance 二是获得classLoader 即
Student.class.getClassLoader() 第三是 执行某一个类的静态代码块 ;由于刚才已经说了,这个语句没有作为任何语句的右值,所以 第一和第二种作用可以排除,剩下的就只有第三个可能了;但问题是加载哪一个类的静态代码块呢,一时想不明白,没办法只好试用着把class.forName注释,结果就不用说了,肯定是通不过了,那唯一的解释就是该句对后面的代码有影响,于是开始看后面的代码,看DriverManage的源代码,终于弄明白了;DriverManagerz在调用getConnection方法之前,保证相应的Driver类已经被加载到jvm中,,并且完成了类的初始化工作;而DriverManger把已经加载的Driver类放到一个集合中,这一步通过registerDriver(java.sql.Driver driver),这里Driver是一个接口,每一个数据库厂商做出了不同的实现,mysql的就是com.mysql.jdbc包下的Driver了,也就是被写烂了的Class.forName("com.mysql.jdbc.Driver")了,最后看了一下Driver的源代码 ,果然在它的静态代码里面调用了DriverManager里面的registerDriver,代码如下
package com.mysql.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver
implements java.sql.Driver
{
static
{
try
{
DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
}
在回头看一下oralce的也类似
package oracle.jdbc;
import oracle.jdbc.driver.OracleDriver;
public class OracleDriver extends oracle.jdbc.driver.OracleDriver
{
}
package oracle.jdbc.driver;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import oracle.jdbc.dbaccess.DBAccess;
import oracle.jdbc.dbaccess.DBError;
import oracle.jdbc.oci.OracleOCIConnection;
public class OracleDriver
implements Driver{
.........
static
{
m_driverAccess.put("thin-server", "oracle.jdbc.thinserver.ServerTTC7Protocol");
m_driverAccess.put("oci-server", "oracle.jdbc.ociserver.ServerOCIDBAccess");
m_driverAccess.put("thin", "oracle.jdbc.ttc7.TTC7Protocol");
m_driverAccess.put("oci8", "oracle.jdbc.oci8.OCIDBAccess");
m_driverAccess.put("oci", "oracle.jdbc.oci8.OCIDBAccess");
m_driverAccess.put("kprb", "oracle.jdbc.kprb.KprbDBAccess");
m_defaultConn = null;
m_defaultDriver = null;
Timestamp localTimestamp = Timestamp.valueOf("2000-01-01 00:00:00.0");
try
{
if (m_defaultDriver == null)
{
m_defaultDriver = new OracleDriver();
DriverManager.registerDriver(m_defaultDriver);
}
}
catch (RuntimeException localRuntimeException)
{
}
catch (SQLException localSQLException)
{
}
}
到这里所有的疑惑都解决了!
最后说一下类的静态代码块在什么时候被执行
1 通常的创建实例 new Student()等等
2 第一次加载这个 类到jvm,如Class.forName,Studeng.class等
注意 ClassLoader.loadclass("xxxxx")并不会触发静态代码的执行;