`
jijun87120681
  • 浏览: 41364 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Class.forName加载数据库驱动深入探讨

    博客分类:
  • java
阅读更多

最近写了个监控系统,需要从各个数据库中获取数据,为了可配行,各个数据库的信息(数据库类型,用户名,密码等)都存放在我们自己的数据库中,

暂时想到的方法就是直接用JDBC代码访问数据库,取数据,然后将数据库连接进行池化。

唉,以前都是J2EE开发,用spring配置使用,这次直接使用JDBC还不太习惯了,OK,不废话了

JDBC步骤:

1.加载数据驱动

 

 

Class.forName("com.mysql.jdbc.Driver");

 

  2. 得到数据库连接

 

 

DriverManager.getConnection(url, user, password);

 

  当时到这步就产生两个疑问:

1. 为什么加载了数据库驱动,就能得到数据库连接,看上面的两行代码,是看出来两者之间联系

2. 除了Class.forName()加载数据库驱动,貌似没有看到过其他加载数据库驱动方式,是否有其他方式?为什么不用其他方式?

OK,问题出来了,就看看问题

 

问题1:

后来结合数据库驱动源代码和JDBC规范了解到,每个数据库驱动,都必须在加载的时候,自己实现数据库驱动注册(注册?貌似前面观察者模式就有注册行为,但是数据库驱动却没有update行为,所以不存在通知)

mysql驱动源代码:

 

 

public class Driver extends NonRegisteringDriver
  implements java.sql.Driver
 {
   public Driver()
    throws SQLException
   {
   }
 
   static
   {
    try
    {
       DriverManager.registerDriver(new Driver());
     } catch (SQLException E) {
      throw new RuntimeException("Can't register driver!");
     }
   }
 }

 

 

DriverManager.registerDriver()代码如下:

 

 

public static synchronized void registerDriver(java.sql.Driver driver)
	throws SQLException {
	if (!initialized) {
	    initialize();
	}
      
	DriverInfo di = new DriverInfo();

	di.driver = driver;
	di.driverClass = driver.getClass();
	di.driverClassName = di.driverClass.getName();

	// Not Required -- drivers.addElement(di);

	writeDrivers.addElement(di); 
	println("registerDriver: " + di);
	
	/* 由于可以注册多个数据库驱动类型,这里更新下数据库驱动 */
	readDrivers = (java.util.Vector) writeDrivers.clone();

    }
 

 

 

 

这样在DriverManager.getConnection()的时候,就可以用到数据库驱动,得到连接了,代码如下

 

 

public static Connection getConnection(String url, 
	String user, String password) throws SQLException {
        java.util.Properties info = new java.util.Properties();

        // Gets the classloader of the code that called this method, may 
	// be null.
	ClassLoader callerCL = DriverManager.getCallerClassLoader();

	if (user != null) {
	    info.put("user", user);
	}
	if (password != null) {
	    info.put("password", password);
	}

        return (getConnection(url, info, callerCL));
    }



private static Connection getConnection(
	String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
	java.util.Vector drivers = null;
        /*
	 * When callerCl is null, we should check the application's
	 * (which is invoking this class indirectly)
	 * classloader, so that the JDBC driver class outside rt.jar
	 * can be loaded from here.
	 */
	synchronized(DriverManager.class) {	 
	  // synchronize loading of the correct classloader.
	  if(callerCL == null) {
	      callerCL = Thread.currentThread().getContextClassLoader();
	   }    
	} 
	 
	if(url == null) {
	    throw new SQLException("The url cannot be null", "08001");
	}
    
	println("DriverManager.getConnection(\"" + url + "\")");
    
	if (!initialized) {
	    initialize();
	}

	synchronized (DriverManager.class){ 
            // 得到注册的驱动
	    drivers = readDrivers;  
        }

	// Walk through the loaded drivers attempting to make a connection.
	// Remember the first exception that gets raised so we can reraise it.
	SQLException reason = null;
	for (int i = 0; i < drivers.size(); i++) {
	    DriverInfo di = (DriverInfo)drivers.elementAt(i);
      
	    // 根据数据库类型判断,得到这次请求的数据库连接
	    if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
		println("    skipping: " + di);
		continue;
	    }
	    try {
		println("    trying " + di);
		Connection result = di.driver.connect(url, info);
		if (result != null) {
		    // Success!
		    println("getConnection returning " + di);
		    return (result);
		}
	    } catch (SQLException ex) {
		if (reason == null) {
		    reason = ex;
		}
	    }
	}
    
	// if we got here nobody could connect.
	if (reason != null)    {
	    println("getConnection failed: " + reason);
	    throw reason;
	}
    
	println("getConnection: no suitable driver found for "+ url);
	throw new SQLException("No suitable driver found for "+ url, "08001");
    }
 

OK,到此问题的答案算是明白了

 

下面,问题2:

加载类的方式几种,目前我想到的就下面几种,不够以后在补充,呵呵:

1. Class.forName()

2. Class.forName().newInstance();

3. new

4.Class.class

5.Class.class.newInstance();

6.Thread.currentThread().getContextClassLoader().loadClass()

可以知道方法2和5都是有点多余,加载的类,还实例化了一个对象出来,可以Pass掉。而3跟前面一个问题一样,实例化了一个对象出来,多此一举,此对象还占据内存。

OK,还剩下三种方法1.4.6,先来分析1和6的区别

 

Class.forName()的源代码如下:

 

 

public static Class<?> forName(String className) 
                throws ClassNotFoundException {
        return forName0(className, true, ClassLoader.getCallerClassLoader());
    }

  调用此方法等效于:

 

  Class.forName(className, true, currentLoader)

第二次参数表示装载类的时候是否初始化该类, 即调用类的静态块的语句及初始化静态成员变量。

 

 

Thread.currentThread().getContextClassLoader().loadClass()的代码如下:

 

public Class<?> loadClass(String name) throws ClassNotFoundException {
	return loadClass(name, false);
    }
 

 

调用此方法等效于调用 loadClass(name,false)

 

 

 

protected synchronized Class<?> loadClass(String name, boolean resolve)
	throws ClassNotFoundException
    {
	// First, check if the class has already been loaded
	Class c = findLoadedClass(name);
	if (c == null) {
	    try {
		if (parent != null) {
		    c = parent.loadClass(name, false);
		} else {
		    c = findBootstrapClassOrNull(name);
		}
	    } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }
            if (c == null) {
	        // If still not found, then invoke findClass in order
	        // to find the class.
	        c = findClass(name);
	    }
	}
	if (resolve) {
	    resolveClass(c);
	}
	return c;
    }
 

 

 

 

此方法使用指定的二进制名称来加载类。此方法的默认实现将按以下顺序搜索类:

 

  1. 调用 findLoadedClass(String) 来检查是否已经加载类。

  2. 在父类加载器上调用 loadClass 方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。

  3. 调用 findClass(String) 方法查找类。

如果使用上述步骤找到类,并且 resolve 标志为真,则此方法将在得到的 Class 对象上调用 resolveClass(Class) 方法。

 

参数:
resolve - 如果该参数为 true,则分析这个类 

 

所以此方法没有初始化类,即没有加载类的静态代码,所以此方法不行

 

 

OK,下面只剩下方法1和4了,方法4加载类会获得编译检查,可以保证此类一定存在,所以无法做到运行时动态加载未知数据库驱动,并且Class.class前面还必须给一个变量赋值才行: Class cc = Class.class

所以加载数据库,大家看到的都是方法1。

好了,到这,收工,呵呵。。。。

 

 

0
0
分享到:
评论

相关推荐

    java连接数据库驱动加载

    根据所提供的文件信息,我们可以详细探讨在Java中如何加载并使用各种数据库驱动来建立与数据库的连接。 ### Java连接数据库:驱动加载与连接建立 #### 1. **MySQL数据库** 对于MySQL数据库,其驱动类名为`...

    java中Class.forName的作用浅谈

    下面我们将深入探讨`Class.forName()`的用途、工作原理以及与`new`关键字的区别。 一、`Class.forName()`的用途 1. **动态加载类**:当需要在程序运行时根据某些条件或用户输入来决定加载哪个类时,`Class.forName...

    jdbc驱动程序实例

    - **Class.forName()**:用于加载特定的JDBC驱动类。 - **DriverManager.getConnection()**:用于建立到数据库的连接。 - **URL**:指定数据库的位置以及连接参数。 - **Connection**:表示与数据库之间的连接。 ##...

    浅析使用JDBC操作MySQL需要添加Class.forName("com.mysql.jdbc.Driver")

    在Java编程中,JDBC(Java Database Connectivity)是用于与各种数据库进行交互的一组接口和类。当我们使用JDBC操作MySQL...然而,对于较旧的项目或较低版本的JDBC,仍然需要使用`Class.forName()`的方式来加载驱动。

    java 加载JDBC驱动程序

    加载JDBC驱动程序是Java应用程序访问数据库的第一步,这个过程涉及到Java的反射机制和Class.forName()方法。下面我们将深入探讨这一主题。 1. **JDBC驱动类型** JDBC驱动分为四种类型: - Type 1: JDBC-ODBC ...

    Java数据库驱动加载问题

    ### Java数据库驱动加载问题 #### SQLServer2000与SQLServer2005加载驱动的相同点与不同点 在Java开发环境中,通过JDBC(Java Database Connectivity)技术可以实现对各种数据库的操作。其中,SQL Server是常用的...

    informix数据库连接驱动jar包

    Class.forName("com.informix.jdbc.IfxDriver"); Connection conn = DriverManager.getConnection(url, username, password); // ... 执行数据库操作 } catch (Exception e) { e.printStackTrace(); } } } ``...

    南大通用数据库驱动 jar 包

    2. **建立连接**:通过JDBC的`Class.forName()`方法加载数据库驱动,例如: ```java Class.forName("com.nudt.jdbc.Driver"); ``` 这里的字符串应替换为实际的驱动类名,确保与jar包中的类名匹配。 3. **获取...

    java_shujuku.rar_JAVA数据库

    1. 加载驱动:使用`Class.forName()`方法加载特定数据库的JDBC驱动,例如: ```java Class.forName("com.mysql.jdbc.Driver"); ``` 2. 创建连接:使用`DriverManager.getConnection()`方法创建数据库连接,参数...

    JAVA_Access.rar_JAVA数据库_java access

    首先需要在系统中配置ODBC数据源,然后在Java代码中通过`Class.forName()`加载对应的驱动,最后使用`DriverManager.getConnection()`创建连接。 - 示例代码: ```java Class.forName("sun.jdbc.odbc....

    java连接各个数据库驱动包

    本文将深入探讨如何使用Java连接这些数据库,并介绍所需的驱动包。 首先,我们来了解一下JDBC。JDBC是Java中的一组接口和类,由Java SE的标准版(Java SE Standard Edition)提供,允许Java应用程序与各种关系型...

    Sqlserver2000,2005,Oracle10g,Mysql,DB2,AS400数据库驱动

    在Java中,加载数据库驱动通常通过`Class.forName()`方法,然后使用`DriverManager.getConnection()`创建数据库连接。此外,Java 6及以上版本引入了Automatic JDBC Driver Registration,可以省略`Class.forName()`...

    sybase 数据库 jdbc 驱动下载

    2. **加载驱动**:使用`Class.forName()`方法加载JDBC驱动。 3. **创建连接**:通过`DriverManager.getConnection()`方法建立与Sybase数据库的连接,需要提供数据库URL、用户名和密码。 4. **创建Statement或...

    Java数据库连接大全

    这里,`Class.forName`用于加载特定的数据库驱动,`DriverManager.getConnection`则负责根据提供的URL、用户名和密码创建数据库连接。`jdbc:oracle:thin:@`协议指示使用Oracle Thin驱动进行连接。 #### 2. Java连接...

    sqlserver2000数据库驱动

    本篇文章将深入探讨"sqlserver2000数据库驱动"这一主题,特别是关于jtds和SQL Server的jar包驱动。 首先,让我们关注一下`jtds`。Jtds(Java JDBC Driver for MS SQL Server and Sybase)是一个开源的Java数据库...

    oracle.mysql.mssql数据库JDBC连接

    这一过程通常通过`Class.forName()`方法完成,该方法会加载指定类到JVM中,并实例化驱动对象。以下是针对三种不同数据库的驱动加载示例: 1. **Microsoft SQL Server** (MSSQL): ```java Class.forName(...

    各种数据库连接的写法以及驱动

    在上述代码中,`Class.forName()`方法用于加载相应的数据库驱动,`DriverManager.getConnection()`则用于建立实际的数据库连接。每个数据库的URL格式略有不同,包含了主机地址、端口、数据库名称和服务名等信息。 ...

    常用数据库驱动[收集].zip

    在Java应用中,使用Oracle JDBC驱动通常涉及Class.forName()加载驱动,DataSource获取连接,并通过CallableStatement或PreparedStatement进行操作。 3. SQL Server驱动: Microsoft SQL Server是另一款广泛使用的...

    各数据库jdbc驱动包

    本文将深入探讨标题中提到的几个数据库及其对应的JDBC驱动包,包括MySQL、Microsoft SQL Server 2000/2005以及Oracle。 首先,MySQL是一款开源、免费的关系型数据库管理系统,广泛应用于Web应用开发。其JDBC驱动包...

Global site tag (gtag.js) - Google Analytics