学习了解 DriverManager 与 DataSource

学习了解 DriverManager 与 DataSource

从校园时期的手动写jdbc,到后面上班各种带前缀的DataSource,虽然对连接数据库已经轻车熟路,不过也是知其然不知其所以然。
最近开始看源码,从简单一点的dbutils看起,加上项目试用动态数据源,于是对jdbc的底层和各种数据库连接工具,必须要有更深入一些的了解。

原生jdbc

  1. 注册驱动,反射方式加载驱动类
  2. 设置url、username、password
  3. 获得连接对象Connection
  4. 获得执行器Statement
  5. 获得执行结果ResultSet
  6. 释放资源

DataSource

这是一个可以获取数据库连接的接口,所以我们需要引用别人写好的实现工具比如dbcp、c3p0等。
获取到数据库连接Connection以后,可以采用跟上述相同的操作,当然我们不会那么做,因为有太多别人造好的轮子给我们助力,比如我现在正在看的dbutils就是比较早期的工具。

重点是数据库连接Connection的获取

1. 通过Driver获取:
Class.forName("com.mysql.jdbc.Driver"),可以简单的理解为新建一个Driver类,就像new Driver()
com.mysql.jdbc.Driver类:

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

可以看到,在类加载以后,就自动向DriverManager中注册自身了。

DriverManager.getConnection(..),获取数据库连接。
无论调用哪个getConnection的重载,最终都会调用同一个方法,所以我们分析下这个方法的源码就可以了。
DriverManager类getConnection方法:

private static Connection getConnection(
        String url, java.util.Properties info, Class<?> caller) throws SQLException {
        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
        synchronized(DriverManager.class) {
            if (callerCL == null) {
                callerCL = Thread.currentThread().getContextClassLoader();
            }
        }
        if(url == null) {
            throw new SQLException("The url cannot be null", "08001");
        }
        println("DriverManager.getConnection(\"" + url + "\")");
        SQLException reason = null;
        for(DriverInfo aDriver : registeredDrivers) {
            if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    println("    trying " + aDriver.driver.getClass().getName());
                    Connection con = aDriver.driver.connect(url, info);
                    if (con != null) {
                        // Success!
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return (con);
                    }
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }

            } else {
                println("    skipping: " + aDriver.getClass().getName());
            }
        }
        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. callerCL 和 caller,类加载器,只需要知道新建类是需要类加载器的就行。
  2. for(DriverInfo aDriver : registeredDrivers),遍历已注册Driver驱动。
  3. isDriverAllowed(aDriver.driver, callerCL),判定该驱动是否适配该数据库(通过比较该结构中的每一个驱动对象的Class和类加载器对象是否相同,如果相同则表示该驱动适配改数据库)
  4. Connection con = aDriver.driver.connect(url, info),获取连接

题外话:不能用加载DriverManager的类加载器,因为DriverManager在rt.jar里面,它的类加载器是启动类加载器。而数据库的driver(com.mysql.jdbc.Driver)是放在classpath里面的,启动类加载器是不能加载的。所以,如果严格按照双亲委派模型,是没办法解决的。而这里的解决办法是:通过调用类的类加载器去加载。而如果调用类的加载器是null,就设置为线程的上下文类加载器。

2. 通过DataSource获取
BasicDataSourceFactory.createDataSource(null) 内部的源码比较复杂就不贴了,总之返回的是BasicDataSource
BasicDataSource获取数据库连接时,使用的是PoolingDataSource的方法,后者里面使用的是数据库连接池。

这里简单列举了一下dbcp的方式,还有比较出名的有c3p0以及阿里的druid

小结

与别人写好的工具框架相比,java的源码实在是简单,不过作为立身之本,其主要是定接口划规范,这也是java能跨平台大行其道的重要原因。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值