`

JAVA JDBC(MySQL)驱动源码分析

    博客分类:
  • java
阅读更多

JAVA连接数据库是其众多功能中的一部分,主要有两种方式连接DataBase: 一种是采用JDBC-ODBC桥,另一种则是称之为纯驱动连接DataBase,第一种方式在大型项目中基本上不再使用,本系列文章主要分析纯驱动源码。
对于初学JAVA者,甚至那些使用JAVA做过几年开发的程序员来讲,对于JDBC的工作原理都不一定能够明白。知其然,不知其所以然。遇到问题就不知所 措了。通过针对于MYSQL JDBC源码的分析,对于JAVA是如何连接数据库,其中到底做了些什么工作,一步步解剖开来,更好的理解JDBC。
使用JAVA连接数据库,首先要做的就是在程序中导入sql包,然后装载驱动类、获取连接、获取语句对象、发送SQL命令然后得到结果
请看以下代码片段:

 

 

package javaT.sql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class MysqlDemo {
    public static void main(String[] args) throws Exception {
        Connection conn = null;
        String sql;
        // MySQL的JDBC URL编写方式:jdbc:mysql://主机名称:连接端口/数据库的名称?参数=值
        // 避免中文乱码要指定useUnicode和characterEncoding
        // 执行数据库操作之前要在数据库管理系统上创建一个数据库,名字自己定,
        // 下面语句之前就要先创建javademo数据库
        String url = "jdbc:mysql://192.168.1.111:3306/appcenter_new?useUnicode=true&characterEncoding=utf8";
 
        try {
            // 之所以要使用下面这条语句,是因为要使用MySQL的驱动,所以我们要把它驱动起来,
            // 可以通过Class.forName把它加载进去,也可以通过初始化来驱动起来,下面三种形式都可以
            Class.forName("com.mysql.jdbc.Driver");// 动态加载mysql驱动
            // or:
//             com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver();
            // or:
//             new com.mysql.jdbc.Driver();
 
            System.out.println("成功加载MySQL驱动程序");
            // 一个Connection代表一个数据库连接
            conn = DriverManager.getConnection(url,"jbjava","jb98");
            // Statement里面带有很多方法,比如executeUpdate可以实现插入,更新和删除等
            Statement stmt = conn.createStatement();
            sql = "create table student(NO char(20),name varchar(20),primary key(NO))";
            int result = stmt.executeUpdate(sql);// executeUpdate语句会返回一个受影响的行数,如果返回-1就没有成功
            if (result != -1) {
                System.out.println("创建数据表成功");
                sql = "insert into student(NO,name) values('2012001','陶伟基')";
                result = stmt.executeUpdate(sql);
                sql = "insert into student(NO,name) values('2012002','周小俊')";
                result = stmt.executeUpdate(sql);
                sql = "select * from student";
                ResultSet rs = stmt.executeQuery(sql);// executeQuery会返回结果的集合,否则返回空值
                System.out.println("学号\t姓名");
                while (rs.next()) {
                    System.out
                            .println(rs.getString(1) + "\t" + rs.getString(2));// 入如果返回的是int类型可以用getInt()
                }
            }
        } catch (SQLException e) {
            System.out.println("MySQL操作错误");
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            conn.close();
        }
 
    }
 
}

 

   

    /* 连接mysql 时装载的驱动类以及连接字符串 */  
    Class.forName(“com.mysql.jdbc.Driver”);//1  
    DriverManager.getConnection(“jdbc:mysql://localhost:3306/test”,”root”,”123”);//2  
    /* 连接SQLServer2005 时装载的驱动类以及连接字符串 */  
    Class.forName(“com.microsoft.sqlserver.jdbc.SQLServerDriver”);  
    DriverManager.getConnection(“jdbc:sqlserver://localhost:1433;databaseName=pubs”,”sa”, ””);  
 

 

此段代码有两部分,连接不同数据库时所需要装载的驱动类以及连接字符串,以此获取连接。
Class.forName()装载类,在调用一个类的构造方法,初始化静态成员或者这个类有main方法时,JVM都会装载对应的类。
首先我们就看看com.mysql.jdbc.Driver类做了什么事情,找到MYSQL-JDBC驱动源码,解压之后找到src目录,然后找到com.mysql.jdbc下的Driver.java类

 

 

    package com.mysql.jdbc;  
    import java.sql.SQLException;  
    public class Driver extends NonRegisteringDriver implements java.sql.Driver {  
        static {  
            try {  
                java.sql.DriverManager.registerDriver(new Driver()); //1  
            } catch (SQLException E) {  
                throw new RuntimeException("Can't register driver!");  
            }  
        }  
        // ~ Constructors  
        // -----------------------------------------------------------  
        /** 
         * Construct a new driver and register it with DriverManager 
         *  
         * @throws SQLException 
         *             if a database error occurs. 
         */  
        public Driver() throws SQLException {  
            // Required for Class.forName().newInstance()  
        }  
    }  
 

Driver类继承NonRegisteringDriver 同时实现接口java.sql.Driver
此类会有一个静态块

 

 

 
    static {  
            try {  
                java.sql.DriverManager.registerDriver(new Driver()); //1  
            } catch (SQLException E) {  
                throw new RuntimeException("Can't register driver!");  
            }  
        }  

 

Class.forName的作用是要求JVM查找并加载指定的类, 也就是说JVM装载此类并执行静态块代码
此静态块只有一句关键部分,1处
在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBC 驱动
的Driver类的代码都必须类似下面这段
java.sql.DriverManager.registerDriver(new Driver());
所以,如果你要自己实现一个数据库的JDBC驱动,那么就得实现java.sql.Driver接口,并且需要在实现类中使用 java.sql.DriverManager.registerDriver(new Driver())注册自己,new Driver()就是创建一个Driver对象,所以此类会有一个无参数的构造函数:

    public Driver() throws SQLException {  
     }  
 

 

下面再看看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);  
          
        /* update the read copy of drivers vector */  
        readDrivers = (java.util.Vector) writeDrivers.clone();  
    }  

 
此方法是一个静态同步的方法,形式参数是java.sql.Driver接口类型,因为com.mysql.jdbc.Driver这个类实现了 java.sql.Driver接口,所以com.mysql.jdbc.Driver实例对象new Driver()是可以作为实参传入到此方法中来的。在DriverManager类中都是使用的Driver接口类型,也就是说驱动的使用不依赖于任何 实现。如果需要更换你所连接的数据库,只需要在Class.forName传入的参数换成另一个数据库的驱动类,但要求此类必须实现Driver接口。

 

上一篇中分析了Class.forName(“com.mysql.jdbc.Driver”)幕后所做的事情,也就是在Driver实现类中的静 态块和构造函数,本篇主要来分析一下静态块的一句代码:DriverManager.registerDriver方法和其它相关的调用。
    registerDriver方法是一个静态方法,它所要做的工作就是加载所有系统提供的驱动,并把它们添加到具体的类中,形成对象。同时还创建连接,是一个管理驱动的工具类。如果我们使用的是mysql,那么加载的也就是它的驱动。
    此方法的源码如下:

 

    public static synchronized void registerDriver(java.sql.Driver driver)  
        throws SQLException {  
        if (!initialized) {  //1  
            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);  
        /* update the read copy of drivers vector */  
        readDrivers = (java.util.Vector) writeDrivers.clone();  
    }  
 

 

一、初始化操作
1、看看1处的代码,判断是否初始化,这个判断的变量是一个静态全局boolean值,初始为false

    private static boolean initialized = false;




如果此变量的值为false那么它将会进入初始化方法,源码如下:

 

 

    static void initialize() {  
            if (initialized) {  
                return;  
            }  
            initialized = true;  
            loadInitialDrivers();  
            println("JDBC DriverManager initialized");  
        }  
 

 

2、Initialize方法中判断initialized值是否为真(其实就是通过此boolean变量判断是否已经初始化完成),之后设置 initialized值为true,接着又会调用另一个方法loadInitialDrivers() 同样是静态方法,用于调用系统类装载器,装载所有系统提供的驱动:
loadInitialDrivers()源码:

 

    private static void loadInitialDrivers() {  
            String drivers;  
          
            try {  
            drivers = (String) java.security.AccessController.doPrivileged(  
            new sun.security.action.GetPropertyAction("jdbc.drivers"));  
            } catch (Exception ex) {  
                drivers = null;  
            }  
              
            // If the driver is packaged as a Service Provider,  
            // load it.  
            // Get all the drivers through the classloader   
            // exposed as a java.sql.Driver.class service.  
          
         DriverService ds = new DriverService();  
         // Have all the privileges to get all the   
         // implementation of java.sql.Driver  
         java.security.AccessController.doPrivileged(ds);  
             println("DriverManager.initialize: jdbc.drivers = " + drivers);  
            if (drivers == null) {  
                return;  
            }  
            while (drivers.length() != 0) {  
                int x = drivers.indexOf(':');  
                String driver;  
                if (x < 0) {  
                    driver = drivers;  
                    drivers = "";  
                } else {  
                    driver = drivers.substring(0, x);  
                    drivers = drivers.substring(x+1);  
                }  
                if (driver.length() == 0) {  
                    continue;  
                }  
                try {  
                    println("DriverManager.Initialize: loading " + driver);  
                    Class.forName(driver, true,  
                      ClassLoader.getSystemClassLoader());  
                } catch (Exception ex) {  
                    println("DriverManager.Initialize: load failed: " + ex);  
                }  
            }  
        }  
 

主要代码分析:
    下面这段创建了一个内部类对象,创建此对象时,它会从系统服务中加载驱动

 

 
    DriverService ds = new DriverService();  
 

 

DriverService内部类的具体代码:

 

    class DriverService implements java.security.PrivilegedAction {  
            Iterator ps = null;  
        public DriverService() {};  
            public Object run() {  
        ps = Service.providers(java.sql.Driver.class);  //从系统服务中加载驱动  
        try {  
               while (ps.hasNext()) { //遍历驱动  
                   ps.next();  
               } // end while  
        } catch(Throwable t) {  
            // Do nothing  
        }  
            return null;  
        } //end run  
    } //end DriverService  
 

 

 

 

此句代码就是找到所有的拥有权限的java.sql.Driver的实现

java.security.AccessController.doPrivileged(ds);  
 

 

下面这段,意思是得到系统属性jdbc.drivers对应驱动的驱动名称,使用了JAVA的安全许可

 

    drivers = (String) java.security.AccessController.doPrivileged(  
            new sun.security.action.GetPropertyAction("jdbc.drivers"));  
 

 

再看看后面的判断和循环
首先判断驱动服务对象是否为null,如果为null则返回,否则进入while循环,这个循环会依次遍历多个数据库驱动,因为jdbc:drivers 会有多个数据库驱动,驱动名是以:分割,接下来就是通过Class.forName依次装载驱动类,在其中使用了 ClassLoader.getSystemClassLoader()系统类装载器。

 

    if (drivers == null) {  
                return;  
            }  
     while (drivers.length() != 0) {  
    …  
    Class.forName(driver, true, ClassLoader.getSystemClassLoader());  
    …  
    }  
 

 

上面分析的就是在registerDriver方法中所要做的第一件事情:初始化。可以看到initialize()做的工作就是装载驱动,同时还 需要使用到系统的一些功能。如: java.security.AccessController.doPrivileged,此方法允许在一个类实例中的代码通知这个 AccessController,它的代码主体享受特权(Privileged),它不管这个请求是由什么代码所引发的,只是单独负责对它可得到的资源 的访问请求。比如说,一个调用者在调用doPrivileged方法时,可被标识为特权。AccessController做访问控制决策时,如果 checkPermission方法遇到一个通过doPrivileged方法调用而被视为特权调用者,那么checkPermission方法不会作许 可检查,表示那个访问请求是被允许的,如果调用者没有许可,则会抛出一个异常。

如:ClassLoader.getSystemClassLoader(),java中所有类都是通过ClassLoader装载的,ClassLoader可以为java程序提供很好的动态特性,有必要去深入理解哦。

接下来再看初始化之后的代码:

 

    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);  
        /* update the read copy of drivers vector */  
        readDrivers = (java.util.Vector) writeDrivers.clone();  
 

 

创建DriverInfo对象
DriverInfo di = new DriverInfo();
DriverInfo驱动信息类,是一个内部类,
源码如下:

 

    class DriverInfo {  
        Driver         driver;  
        Class          driverClass;  
        String         driverClassName;  
        public String toString() {  
        return ("driver[className=" + driverClassName + "," + driver + "]");  
        }  
    }  
 

 

此类就是添加了三个属性,分别表示驱动对象,驱动的Class对象,以及驱动的类名;同时重写了toString方法。此内部类的作用就是以可以创建DriverInfo对象,以对象的形式保存驱动信息。

接下来就是设置对象的三个属性:

 

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

 

然后添加到集合writeDrivers中,这个集合是Vector类型,定义为DriverManager的属性

writeDrivers定义:

 

 
    private static java.util.Vector writeDrivers = new java.util.Vector();  

 

驱动添加到集合

 

 
writeDrivers.addElement(di);  

 

最后就是调用writeDrivers对象的clone方法

 

 
readDrivers = (java.util.Vector) writeDrivers.clone();  

 


readDrivers也是一个类型为Vector的集合,定义为DriverManager的属性

 

    private static java.util.Vector readDrivers = new java.util.Vector();  
 

 

为什么要先添加到writeDrivers然后再 clone到readDrivers中呢?
writeDrivers和 readDrivers两个都是驱动集合,无论是注册驱动抑或是取消注册,都是先对writeDrivers驱动集合中的数据进行添加或删除,然后再把 writeDrivers中的驱动都clone到readDrivers中,每次取出Driver并不是在writeDrivers中,而是在 readDrivers中取得。那么这两个驱动集合便可以这样理解,writeDrivers驱动集合负责注册驱动和注销驱动,readDrivers驱 动集合负责提供可用的驱动对象,readDrivers中的驱动对象应该都是可用的。把二者分开,使用者就不需加任何判断,很方便。
这里又涉及到一个知识就是clone, 有兴趣的朋友可以查看相关JAVA文档,Thinking in java 中也有详细描述。
这就是初始化的全过程,写了这么多,实际上只做一件事情,就是完成所有驱动的加载。装载之后就是连接了,在连载三当中我会详细描述。

 

第二篇中讲解了如何装载驱动,以及它的初始化过程。
本篇分析一下连接数据库时使用的获取数据库连接的代码:

 

    DriverManager.getConnection(“jdbc:mysql://localhost:3306/test”,”root”,”123”);  
 

 

DriverManager.getConnection方法有三种重载方式,这里我们使用带有三个参数的方法,第一个表示数据库的URL, 第二、三个分别
是用户名和密码。获取数据库连接如此简单,只要把三个参数准确无误的写上去,连接肯定就能获取。但是连接方法中到底给我们做
了哪些工作呢? 下面找到DriverManager类的静态方法getConnection源码一探究竟。

 

    public static Connection getConnection(String url,   
        String user, String password) throws SQLException {  
            java.util.Properties info = new java.util.Properties(); ///1  
            // Gets the classloader of the code that called this method, may   
        // be null.  
        ClassLoader callerCL = DriverManager.getCallerClassLoader(); ///2  
        if (user != null) {  
            info.put("user", user);  
        }  
        if (password != null) {  
            info.put("password", password);  
        }  
            return (getConnection(url, info, callerCL)); ///3  
        }  
 

 

1处定义了一个Properties对象,java.util.Properties它是用来在文件中存储键值对的,其中键和值是用等号分隔的。可以将值以
key-value的形式存入Properties.
2处调用方法getCallerClassLoader得到类装载器对象, 这个地方有点意思,既然是调用方法,怎么变成了下面这种形式呢?根本就
不见方法体。
源码:

    private static native ClassLoader getCallerClassLoader();  
 

 

getCallerClassLoader()是一个静态原生方法,返回类型为ClassLoader, 被声明为native, 说明这个方法是一个原生方法,也就是说
这个方法是用C/C++语言实现的,并且被编译成了DLL,由JAVA调用。这些函数的实体在DLL中,JDK源码并不包含,在JAVA源文件中是
找不到源代码的。不同的平台其实现也有所差异。这也是JAVA的底层机制,实际上JAVA就是在不同的平台上调用不同的native方法实
现对操作系统的访问。native关键字一般是和C/C++联合开发的时候使用。如果标明为native 要求运行时通知操作系统,这个函数必
须给我实现,JAVA需要调用。如果未实现,那么调用时会抛出一个异常java.lang.UnsatisfiedLinkError
接下来判断用户名和密码,并将其存放到Properties对象中:

 

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

 

调用获取连接的另一个重载方法

 

getCollection(String url, java.util.Properties info, ClassLoader callerCL)

 

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

 

 

getConnection(url, info, callerCL) 源码:

 

  private static Connection getConnection(  
String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {  
java.util.Vector drivers = null;  
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){   
           // use the readcopy of drivers  
    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 the caller does not have permission to load the driver then   
    // skip it.  
    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");  
   }  
 

 

此方法代码较多,我们一步步来分析。
1、    传参
从前面的那个getConnection方法中形成的三个参数传递到这个getConnection方法中, 参数包括连接数据库的URL,包装了用户名和
密码的对象info, 通过调用原生函数返回的类装载器callerCL
2、    同步DriverManager.class
同步DriverManager的Class对象,synchronized同步的对象为DriverManager.class,是为同步正确的类加载器来加载类,在同步块
中判断传入的类装载器对象是否存在,如果为null, 通过当前线程来获取上下文类装载器,保证JDBC驱动程序类以外的rt.jar中的类
可以在这里被加载。有关于Thread和synchronized读者可以参考java多线程编程

 

    synchronized(DriverManager.class) {    
          if(callerCL == null) {  
              callerCL = Thread.currentThread().getContextClassLoader();  
           }  
        }   
 

 

3、    判断URL,如果为null则抛出SQLException异常
判断initialized的值,如果未初始化,继续调用初始化方法,此处在第二篇中已详细解释初始化过程,初始化之后writeDrivers 和readDrivers 将会有系统所有驱动数据,接下来使用synchronized同步DriverManager.class对象, 将方法中定义的集合drivers 引用 readDrivers对象,readDrivers是从writeDrivers拷贝过来

 

    if(url == null) {  
        throw new SQLException("The url cannot be null", "08001");  
    }  
    println("DriverManager.getConnection(/"" + url + "/")");  
    if (!initialized) {  
    initialize();  
    }  
    synchronized (DriverManager.class) {   
        // use the readcopy of drivers  
    drivers = readDrivers;    
     }  

 
4、    遍历驱动

通过for循环,遍历drivers集合,其中每个元素的类型为DriverInfo, 这个在第二篇中也有详细描述
首先取得集合中的每一个对象元素,调用getCallerClass()方法

 

  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;  
        }  
……  
}  
 

 

getCallerClass方法源码:

    private static Class getCallerClass(ClassLoader callerClassLoader,   
                        String driverClassName) {  
    Class callerC = null;  
    try {  
    callerC = Class.forName(driverClassName, true, callerClassLoader);  
    }  
    catch (Exception ex) {  
            callerC = null;             
        }  
        return callerC;  
        }  
 

 

    这个方法返回一个Class对象,通过指定的类装载器来装载驱动类。这个方法内做得非常小心,如果出现异常都会把需要返
回的Class对象置为null.
    在if语句中调用getCallerClass方法得到的Class 对象和每一个驱动的Class对象比较,不相等的话就继续执行下一次循环
,否则都调用Driver的connect方法,传入url, 和 info,通过这个方法返回Connection连接对象

Connection result = di.driver.connect(url, info);   

Driver接口的实现类中的connect方法具体所做的工作将在下一篇中详述

 

connect 方法是java.sql.Driver接口中定义的方法,如果连接的数据库不同,那么为不同的数据库编写JDBC驱动将变得很灵活,实现Driver接口 即可。连接数据库时首先得装载JDBC驱动,也就是调用 Class.forName(“com.mysql.jdbc.Driver”)方法,在第一篇中已经列出mysql jdbc Driver类的源码,此类继承NonRegisteringDriver同时实现了java.sql.Driver接口。找到 NonRegisteringDriver类会发现它也实现了java.sql.Driver接口:

 

 
    public class NonRegisteringDriver implements java.sql.Driver {  
        ……  
    }  

 


在getConnection方法中有如下一句代码,
Connection result = di.driver.connect(url, info);

di是DriverInfo类型的对象,此对象中包含了Driver的引用,但是在com.mysql.jdbc.Driver类中只有一个静态块和一个 构造方法,那么connect方法有可能是在其父类中实现。如前所述,父类为NonRegisteringDriver,在mysql驱动包的源码中可以 找到此类,:
com.mysql.jdbc.NonRegisteringDriver

那么di.driver.connect(url, info) 调用的connect方法就是NonRegisteringDriver类中的connect方法,源码如下:

 

 

    public java.sql.Connection connect(String url, Properties info)  
                throws SQLException {  
            if (url != null) {  
                if (StringUtils.startsWithIgnoreCase(url, LOADBALANCE_URL_PREFIX)) {  
                    return connectLoadBalanced(url, info);  
                } else if (StringUtils.startsWithIgnoreCase(url,  
                        REPLICATION_URL_PREFIX)) {  
                    return connectReplicationConnection(url, info);  
                }  
            }  
            Properties props = null;  
            if ((props = parseURL(url, info)) == null) {  
                return null;  
            }  
            try {  
                Connection newConn = com.mysql.jdbc.ConnectionImpl.getInstance(  
                        host(props), port(props), props, database(props), url);  
                return newConn;  
            } catch (SQLException sqlEx) {  
                // Don't wrap SQLExceptions, throw  
                // them un-changed.  
                throw sqlEx;  
            } catch (Exception ex) {  
                SQLException sqlEx = SQLError.createSQLException(Messages  
                        .getString("NonRegisteringDriver.17") //$NON-NLS-1$  
                        + ex.toString()  
                        + Messages.getString("NonRegisteringDriver.18"), //$NON-NLS-1$  
                        SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE, null);  
                  
                sqlEx.initCause(ex);  
                  
                throw sqlEx;  
            }  
        }  
 

 

在connect方法中传入了两个参数,一个是String 类型的url, 另一个是Properties类型的连接属性信息。
首先判断url是否为null,此判断逻辑中使用了如下类的方法
调用类com.mysql.jdbc.StringUtils
方法 startsWithIgnoreCase 其中使用了String 类中的方法regionMatches
regionMatches方法两种原型为:

 

 

    public boolean regionMatches(int toffset, String other,   
    int ooffset,int len) { }  
    public boolean regionMatches(boolean ignoreCase, int toffset,  
                               String other, int ooffset, int len) {}  

 
这两个重载的方法用来比较两个字符串中指定区域的子串。

 


传入的静态常量参数:

 

 

    private static final String LOADBALANCE_URL_PREFIX = "jdbc:mysql:loadbalance://";  
    private static final String REPLICATION_URL_PREFIX = "jdbc:mysql:replication://";  
 

 

根据下面的判断调用不同的方法返回Connection对象

 

 

    if (StringUtils.startsWithIgnoreCase(url, LOADBALANCE_URL_PREFIX)) {  
                    return connectLoadBalanced(url, info);  
                } else if (StringUtils.startsWithIgnoreCase(url,  
                        REPLICATION_URL_PREFIX)) {  
                    return connectReplicationConnection(url, info);  
                }  
 

 

如果url为null, 则通过如下方法返回Connection

    try {  
        Connection newConn = com.mysql.jdbc.ConnectionImpl.getInstance(  
                        host(props), port(props), props, database(props), url);  
                return newConn;  
            } catch (SQLException sqlEx) {  
                ……  
            } catch (Exception ex) {  
                  ……  
    }  
    }  
 

 

 

 

未完待续......

(选自 http://blog.csdn.net/brilliancezhou/article/details/5425655)

 


分享到:
评论
1 楼 LyAn_爱踢爱死 2014-04-15  
有没有mySQL JDBC的源码包 共享一下啊

相关推荐

    JAVA上百实例源码以及开源项目源代码

    Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来...

    JAVA上百实例源码以及开源项目

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    sharding-jdbc-1.5.1:sharding-jdbc原始码解析

    分片JDBC-分片数据库和表的JDBC驱动程序 概述 分片JDBC是JDBC的扩展,提供了诸如分片,读/写拆分和BASE事务之类的分布式功能。 特征 1.分片 分布式数据库中支持的聚合功能,分组依据,排序依据和限制SQL。 支持联接...

    MySQL 5.1中文手冊

    2.8.6. 在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级MySQL 2.10.1. 从...

    MySQL 5.1官方简体中文参考手册

    2.8.6. 在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级MySQL 2.10.1. 从...

    MySQL 5.1参考手册

    2.8.6. 在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级MySQL 2.10.1. 从...

    MySQL 5.1参考手册中文版

    2.8.6. 在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级MySQL ...

    mysql5.1中文手册

    在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级...

    MySQL 5.1参考手册 (中文版)

    2.8.6. 在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级MySQL 2.10.1. 从...

    MYSQL中文手册

    2.8.6. 在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级MySQL ...

    毕业设计:Java项目之jsp学生社团管理系统(源码 + 数据库 + 说明文档)

    2.2.5 JDBC驱动介绍 4 2.2.6软硬件需求 5 第3章 软件需求分析 5 3.1功能需求 5 3.1.1功能划分 5 3.1.2功能描述 6 3.2外部接口需求 6 3.2.1用户界面 6 第4章 软件概要设计 7 4.1总体设计 7 4.1.1处理流程 7 4.1.2总体...

    mysql官方中文参考手册

    2.8.6. 在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级MySQL 2.10.1. 从...

    MySQL5.1参考手册官方简体中文版

    2.8.6. 在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级MySQL 2.10.1. 从...

    图书馆管理系统(Java) 优秀毕业设计论文+软件设计源码.zip

    本系统中通过JDBC驱动和数据库进行无缝连接,后端的数据库是mysql,也是一个开源的数据库系统,该数据库具有较高的完整性,一致性和安全性。 关键词:图书管理;信息管理;jsp;struts 绪 论 1.1毕业设计主要任务 ...

Global site tag (gtag.js) - Google Analytics