`

参考Mysql JDBC 驱动源码实现自定义驱动

    博客分类:
  • java
 
阅读更多

一、分析Mysql JDBC

平常我们直接以JDBC连接数据库代码基本都如下:

    Connection con = null;  //创建用于连接数据库的Connection对象  
        try {  
            Class.forName("com.mysql.jdbc.Driver");// 加载Mysql数据驱动  
              
            con = DriverManager.getConnection(  
                    "jdbc:mysql://localhost:3306/myuser", "root", "root");// 创建数据连接  
              
        } catch (Exception e) {  
            System.out.println("数据库连接失败" + e.getMessage());  
        }  
        return con; //返回所建立的数据库连接  

 

1、我们使用Mysql JDBC的时候需要先注册加载驱动:

 

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

 

 利用jdk反射机制的真实注册过程如下:

package com.mysql.jdbc;  
  
import java.sql.SQLException;  
public class Driver extends NonRegisteringDriver implements java.sql.Driver {  
      
       //执行这个静态代码块  
    static {  
        try {//注册mysql实现的驱动类  
            java.sql.DriverManager.registerDriver(new Driver());  
        } catch (SQLException E) {  
            throw new RuntimeException("Can't register driver!");  
        }  
    }  
  
    public Driver() throws SQLException {  
        // Required for Class.forName().newInstance()  
    }  
}  

 接着我们进入java.sql.DriverManager.registerDirver(new Driver())源码:

    /**
     * Registers the given driver with the <code>DriverManager</code>.
     * A newly-loaded driver class should call
     * the method <code>registerDriver</code> to make itself
     * known to the <code>DriverManager</code>.
     *
     * @param driver the new JDBC Driver that is to be registered with the
     *               <code>DriverManager</code>
     * @exception SQLException if a database access error occurs
     */
    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();
	drivers.addElement(di);//注册到驱动集合
	println("registerDriver: " + di);
    }

 再进行一些细节的初始化工作驱动就注册加载完成了,有兴趣可自己看源码。接着我们如何创建连接。

 

2、创建数据连接

 

Drivermanager.getConnection(url,name,password)

 我们进去看看这个方法的实际执行过程

    public static synchronized 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));//①
    }
 接着我们再看①处的代码执行过程
    //  Worker method called by the public getConnection() methods.
    private static synchronized Connection getConnection(
	String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
	
        /*
	 * 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.
	 */
	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();
	}

	// 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;
		}
	    }
	}
 所以上面的①处的代码实际执行的就是com.mysql.jdbc.Driver的connect(url,info)方法
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;  
        }  
  
        if (!"1".equals(props.getProperty(NUM_HOSTS_PROPERTY_KEY))) {  
            return connectFailover(url, info);  
        }  
          
        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;  
        }  
    }  
二、自定义驱动 
		Class.forName("org.tinygroup.dbrouterjdbc3.jdbc.TinyDriver");
		conn = DriverManager.getConnection("jdbc:dbrouter://aggregate", "ljf",
				"123456");
 1、注册加载驱动
public class TinyDriver implements Driver {

    private RouterManager manager;

    private Logger logger = LoggerFactory.getLogger(TinyDriver.class);

    static {
        try {
            DriverManager.registerDriver(new TinyDriver());//注册驱动
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    public TinyDriver() {
        manager = RouterManagerBeanFactory.getManager();
    }
 我们再来看看如何获得数据连接
    public Connection connect(String url, Properties info) throws SQLException {
        if (!acceptsURL(url)) {
            return null;
        }
        String routerName = url.substring("jdbc:dbrouter://".length());
        Router router = manager.getRouter(routerName);
        String user = info.getProperty("user");
        String password = info.getProperty("password");
        if (!user.equals(router.getUserName())) {
            logger.logMessage(LogLevel.ERROR,
                    "username {0} and {1} not equals", user,
                    router.getUserName());
            throw new SQLException("username not equals");
        }
        if (!password.equals(router.getPassword())) {
            logger.logMessage(LogLevel.ERROR,
                    "password {0} and {1} not equals", password,
                    router.getPassword());
            throw new SQLException("password not equals");
        }
        return new TinyConnection(routerName);
    }
 通过以上的分析我们可以通过对JDBC进行包装就能做到多数据源,甚至可以在JDBC层上进行分库分表。这样做的好处是对于上层开发人员是透明的。

 

分享到:
评论

相关推荐

    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参考手册

    MySQL 5.1参考手册.chm 前言 1. 一般信息 1.1. 关于本手册 1.2. 本手册采用的惯例 1.3. MySQL AB概述 1.4. MySQL数据库管理系统概述 1.4.1. MySQL的历史 1.4.2. MySQL的的主要特性 1.4.3. MySQL稳定性 1.4.4. MySQL...

    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 ...

    mysql官方中文参考手册

    MySQL 5.1参考手册 目录 前言 1. 一般信息 1.1. 关于本手册 1.2. 本手册采用的惯例 1.3. MySQL AB概述 1.4. MySQL数据库管理系统概述 1.4.1. MySQL的历史 1.4.2. MySQL的的主要特性 1.4.3. MySQL稳定性 1.4.4. ...

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

    MySQL 5.1参考手册 这是MySQL参考手册的翻译版本,关于MySQL参考手册,请访问dev.mysql.com。 原始参考手册为英文版,与英文版参考手册相比,本翻译版可能不是最新的。 This translation was done by MySQL ...

    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. 从...

    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. 升级...

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

     //给客户发一个感谢消息,消息驱动Bean必须实现两个接口MessageDrivenBean和MessageListener  在对象创建的过程中将被容器调用,onMessage函数方法接收消息参数,将其强制转型为合适的消息类型,同时打印出消息...

    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上百实例源码以及开源项目

     //给客户发一个感谢消息,消息驱动Bean必须实现两个接口MessageDrivenBean和MessageListener  在对象创建的过程中将被容器调用,onMessage函数方法接收消息参数,将其强制转型为合适的消息类型,同时打印出消息...

    好用的代码生成源码

    配置classpath,将generator/lib中的rapid-generator.jar及其它数据库驱动加入classpath 修改generator.xml的数据库连接属性及其它属性 以application的方式运行GeneratorMain类,要生成不同的table,直接修改代码即可 ...

    疯狂JAVA讲义

    10.4.2 自定义异常类 371 10.4.3 catch和throw同时使用 371 10.4.4 异常链 373 10.5 Java的异常跟踪栈 374 10.6 异常处理规则 376 10.6.1 不要过度使用异常 377 10.6.2 不要使用过于庞大的try块 378 10.6.3 ...

    玩转模板--自动代码生成工程

    工程提供所有源码,包括第三方jar包也附带源码包 注意事项: 1.需要一定的java开发基础. 2.要有java开发的集成环境,本工程没有界面,很多功能都是通过直接注释,或增加一些代码完成. 3.JDK版本必须是1.6以上,否则会报...

    ssh(structs,spring,hibernate)框架中的上传下载

     fileContent字段映射为Spring所提供的BlobByteArrayType类型,BlobByteArrayType是用户自定义的数据类型,它实现了Hibernate 的org.hibernate.usertype.UserType接口。BlobByteArrayType使用从sessionFactory获取...

    Python Cookbook

    16.6 使用内建的Tokenizer给Python源码上色 572 16.7 合并和拆解Token 575 16.8 检查字符串是否有平衡的圆括号 577 16.9 在Python中模拟枚举 580 16.10 在创建列表推导时引用它自身 583 16.11 自动化py2exe将...

    jpivot学习总结.doc

    1. jpivot加入其它应用中 解压jpivot.war 文件,在你的应用当中你需要下面的这些文件:... jdbcUrl="jdbc:mysql://localhost/foodmart" catalogUri="/WEB-INF/test/FoodMart.xml"&gt; select {[Measures].[Unit Sales]...

Global site tag (gtag.js) - Google Analytics