为什么需要Class.forName("com.mysql.jdbc.Driver")
在使用传统的JDBC连接数据库的时候,总是需要这一句(以MySQL为例):
Class.forName("com.mysql.jdbc.Driver");
以前我也没深究,只是看网上的例子都这么写,实际上也跑通了,于是便懒得去管内部原理。不过大概还是清楚的,知道这句话是向DriverManage注册了一个MySQL的JDBC Driver。
但为什么要用Class.forName这样看上去不是很优雅的方式呢?
网上还流传了一个这样的版本Class.forName("com.mysql.jdbc.Driver").newInstance(),似乎有点儿多此一举。
经过实验,我发现用com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver() 也是可以的,但是只声明
com.mysql.jdbc.Driver driver = null ,而不实例化却又是不行的。
那么Driver的注册到底是在类的初始化时进行的,还是在类的对象初始化时进行的呢? 我也不知道,最好的办法还是看源码:
package com.mysql.jdbc;
import java.sql.DriverManager; import java.sql.SQLException;
// Referenced classes of package com.mysql.jdbc: // NonRegisteringDriver
public class Driver extends NonRegisteringDriver {
public Driver() throws SQLException { }
static { try { DriverManager.registerDriver(new Driver()); } catch(SQLException E) { throw new RuntimeException("Cant register driver!"); } } }
源码之前没秘密,com.mysql.jdbc.Driver很简单,就是红色的那句,看来是在类的static block里面做的初始化。
那么我们只要搞清楚在java里面,static block执行的时机就可以清楚来龙去脉了。
还是做一个实验吧:package com.javaye;
class A{ static{ System.out.println("Class A loaded"); } public A(){ System.out.println("create a instance of A"); } }
public class Main { public static void main(String[] args) throws Exception{ Class.forName("com.javaye.A"); } }
打印结果:“Class A loaded”
这说明Class.forName可以使类的static block中的代码得到执行。
然后,我们在修改成下面这样:
package com.javaye;
class A{ static{ System.out.println("Class A loaded"); } public A(){ System.out.println("create a instance of A"); } } public class Main { public static void main(String[] args) throws Exception{ com.javaye.A a = null; } }
发现没有打印任何东西,这说明只是声明某个类的变量,是不会使static block的到执行的。
再改一下:
package com.javaye;
class A{ static{ System.out.println("Class A loaded"); } public A(){ System.out.println("create a instance of A"); } } public class Main { public static void main(String[] args) throws Exception{ com.javaye.A a = new com.javaye.A(); com.javaye.A a2 = new com.javaye.A(); } }
输出结果:
Class A loaded create a instance of A create a instance of A
这说明实例化一个类的话,static block 也会被执行,而且只会被执行一遍。
package data;
import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException;
import com.mysql.jdbc.Connection; import com.mysql.jdbc.Statement;
public class MySql { private static String url="jdbc:mysql://127.0.0.1:3306/mydata"; private static String user="test"; private static String password="123"; public static void main(String [] args) { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); }// 加载驱动 Connection conn = null; Statement stmt = null; ResultSet rs = null; try { conn = (Connection) DriverManager.getConnection(url, user, password);// 建立连接 stmt = (Statement) conn.createStatement();
String sql = "select * from role"; rs = stmt.executeQuery(sql);
while (rs.next()) {// 从结果集中取出数据 System.out.print(rs.getInt(1) + "/t"); System.out.print(rs.getString(2) + "/t"); System.out.print(rs.getString(3) + "/n"); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); }// 执行sql语句
System.out.println("Start to do it/n"); } }