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
JDBC在getConnection之前为什么要调用Class.forName(转)的更多相关文章
- JDBC对MySQL数据库存储过程的调用
一.MySQL数据库存储过程: 1.什么是存储过程 存储过程(英文:Stored Procedure)是在大型数据库系统中,为了完成特定功能而编写的一组的SQL语句集.存储过程经编译存储在数据库中,用 ...
- JDBC学习2:为什么要写Class.forName("XXX")?
Class.forName(String name) 接上一篇JDBC.本来这个内容是放在前面的一篇里面的一起的,后来发现越写越多,想想看就算了,还是单独开一篇文章好了,这样也能写得更加详细点. 上一 ...
- 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 ...
- 调用Class.forName()要抛出异常
今天学JDBC时,用到下面的程序: package bo; import java.sql.Connection; import java.util.ArrayList; import java.ut ...
- 为什么要使用class.forname在DriverManager.getConnection之前
JDBC在getConnection之前为什么要调用Class.forName 获取一个数据库连接的通用模板如下: String driver = "oracle.jdbc.OracleDr ...
- eclipse 连接数据库记录
两篇很好的文章介绍给大家: Eclipse使用JDBC方式连接SQLServer2016 通过Driver与DriverManager连接数据库 --------------------------- ...
- Class.forName和registerDriver的区别
我们都知道JDBC的代码怎么写,比如以MySQL JDBC为例 //注册JDBC驱动 Class.forName("com.mysql.jdbc.Driver"); //然后就可以 ...
- 在Jena框架下基于MySQL数据库实现本体的存取操作
在Jena框架下基于MySQL数据库实现本体的存取操作 转自:http://blog.csdn.net/jtz_mpp/article/details/6224311 最近在做一个基于本体的管理系统. ...
- JDBC调用存储过程
一. JDBC调用存储过程 (1)使用存储过程SQL编写的程序代码,等一段语句和控制流语句.在创建时被编译成机器代码和存储在数据库中的client转让. 存储过程具有以下优势: 1.所生成的机器代码被 ...
随机推荐
- C#-循环滚动字幕,timer,从左至右,从右至左,暂停---ShinePans
Lable的Left属性是能够更改的,可是 Right属性不能够更改,所以我们能够利用 这个特点做自加 自减运算 using System; using System.Collections.Gene ...
- c++ 对象指针参数和对象引用参数02
对象指针作为函数参数和对象引用作为函数参数都比对象作为函数参数要用的更为普遍 传对象指针和传对象引用作为实参,那么实参在函数里发生了变话,那么相应的对象本身也会发生变化,二传递对象本身作为实参的话,实 ...
- Android-IA Power Manager (S3)
Sleep and wake up
- C/S与B/S谁与争锋之我见
看到网上有些人在讨论C/S架构和B/S架构以及它们的发展趋势,后起之秀B/S是否真将取代C/S而存在?在发表我的观点之前,我们先来一起来回顾下C/S以及B/S. 一C/S 1.C/S概念 C/S是Cl ...
- extjs在form表单提交成功、故障响应信息
类别Ext.form.Action.Submit 处理表单Form数据并返回response类对象. 这个类的仅在形式实例Form{@link Ext.form.BasicForm#submit 提交 ...
- HTML 5最终确定,八年后,我们再谈谈如何改变世界
从原:http://www.36kr.com/p/216655.html 我们第一次谈论HTML5要改变世界大概是由于乔布斯,他坚持在iOS上不兼容Flash,在Adobe统治多媒体开发的那个年代.这 ...
- 从零开始学Xamarin.Forms(五) 技巧
原文:从零开始学Xamarin.Forms(五) 技巧 由于HTML5规范于2014年10月终于定稿,公司.net开发人员较少,国内外已有了较为成熟的UI框架.手机软件硬件的快速发展等等原因,所以我就 ...
- erlang集群IP及port管理
erlang集群是依靠epmd维护的,epmd是erlang集群节点间port映射的守护进程.负责维护集群内的节点连接.提供节点名称到IP地址及port的解析服务. epmd 自己定义port号 ep ...
- 懒人模式Singleton模式Meyers版本号
直接看代码: /* Singleton模式保证:在一个程序,,一个类有且只有一个实例.并提供一个访问 它的全局访问点 在编程其中.很多情况下,需要确保有一类的一个实例 比如: windopws系统中仅 ...
- 重新想象 Windows 8 Store Apps (18) - 绘图: Shape, Path, Stroke, Brush
原文:重新想象 Windows 8 Store Apps (18) - 绘图: Shape, Path, Stroke, Brush [源码下载] 重新想象 Windows 8 Store Apps ...