博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
jdbc详解:2、DriverManager管理多个数据库驱动
阅读量:7144 次
发布时间:2019-06-29

本文共 8027 字,大约阅读时间需要 26 分钟。

  hot3.png

前一篇地址:

先上代码

static String driverName = "com.mysql.jdbc.Driver";    static String url = "jdbc:mysql://127.0.0.1:3306/mysql";    static String username = "root";    static String password = "";    @Test    public void getConnection1() {        DriverManager.setLogWriter(new PrintWriter(System.out));        try {            // 1、加载驱动,不加载驱动依然正常可以连接            // Class.forName(driverName);            // 2、获取connection            Connection conn = DriverManager.getConnection(url, username, password);            // 3、依然可以获取链接            System.out.println(conn);            // 查看已经加载的driver            Enumeration
drivers = DriverManager.getDrivers(); System.out.println("------加载的diver--------"); while(drivers.hasMoreElements()) { System.out.println(drivers.nextElement().getClass().getName()); } } catch (Exception e) { e.printStackTrace(); } }

上面代码,没有手动加载驱动,但是依然可以获取连接

控制台输出信息

DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql")    trying com.mysql.jdbc.DrivergetConnection returning com.mysql.jdbc.Drivercom.mysql.jdbc.JDBC4Connection@72d8c235------加载的diver--------com.mysql.jdbc.Drivercom.mysql.fabric.jdbc.FabricMySQLDriver

从输出可以看到,DriverManager自动加载了com.mysql.jdbc.Driver和com.mysql.fabric.jdbc.FabricMySQLDriver这两个驱动,这也可以说明DriverManager可以管理多个驱动。

下面我们来看一下DriverManager的源码:

public class DriverManager {    static {        // 类加载时候就进行了加载数据库操作        loadInitialDrivers();        println("JDBC DriverManager initialized");    }        //其他代码省略        private static void loadInitialDrivers() {        String drivers;        try {            // AccessController.doPrivileged这个方法可以看做临时扩大该类的权限            // 读取系统jdbc.drivers的配置            drivers = AccessController.doPrivileged(new PrivilegedAction
() { public String run() { return System.getProperty("jdbc.drivers"); } }); } catch (Exception ex) { drivers = null; } AccessController.doPrivileged(new PrivilegedAction
() { public Void run() { // 扫描 java.sql.Driver的实现类,并加载 // 加载就按照前一篇文章一样进行驱动注册 ServiceLoader
loadedDrivers = ServiceLoader.load(Driver.class); Iterator driversIterator = loadedDrivers.iterator(); try{ while(driversIterator.hasNext()) { driversIterator.next(); } } catch(Throwable t) { // Do nothing } return null; } }); println("DriverManager.initialize: jdbc.drivers = " + drivers); if (drivers == null || drivers.equals("")) { return; } // 加载System中的jdbc.drivers参数指定的驱动,可以是多个驱动,以“:”分割 String[] driversList = drivers.split(":"); println("number of Drivers:" + driversList.length); for (String aDriver : driversList) { try { println("DriverManager.Initialize: loading " + aDriver); Class.forName(aDriver, true, ClassLoader.getSystemClassLoader()); } catch (Exception ex) { println("DriverManager.Initialize: load failed: " + ex); } } } }

加载mysql和oracle驱动,分别连接到mysql和oracle数据库

static String MYSQL_DRIVERNAME = "com.mysql.jdbc.Driver";    static String MYSQL_URL = "jdbc:mysql://127.0.0.1:3306/mysql";    static String MYSQL_USERNAME = "root";    static String MYSQL_PASSWORD = "";    static String ORALE_DRIVERNAME = "oracle.jdbc.driver.OracleDriver";    static String ORALE_URL = "jdbc:oracle:thin:@10.211.55.6:1521:ORCL";    static String ORALE_USERNAME = "system";    static String ORALE_PASSWORD = "orcl";    @Test    public void getConnection1() {        // 输出DriverManager 的日志信息到控制台        DriverManager.setLogWriter(new PrintWriter(System.out));        // 获取mysql连接        try {            // 1、加载驱动            Class.forName(MYSQL_DRIVERNAME);            // 2、获取connection            Connection conn = DriverManager.getConnection(MYSQL_URL, MYSQL_USERNAME, MYSQL_PASSWORD);            System.out.println(conn);        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (SQLException e) {            e.printStackTrace();        }        // 获取oracle连接        try {            // 1、加载驱动            Class.forName(ORALE_DRIVERNAME);            // 2、获取connection            Connection conn = DriverManager.getConnection(ORALE_URL, ORALE_USERNAME, ORALE_PASSWORD);            System.out.println(conn);        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (SQLException e) {            e.printStackTrace();        }    }

执行,控制台输出

DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql")    trying com.mysql.jdbc.DrivergetConnection returning com.mysql.jdbc.Drivercom.mysql.jdbc.JDBC4Connection@22b3428eDriverManager.getConnection("jdbc:oracle:thin:@10.211.55.6:1521:ORCL")    trying com.mysql.jdbc.Driver    trying com.mysql.fabric.jdbc.FabricMySQLDriver    trying oracle.jdbc.OracleDrivergetConnection returning oracle.jdbc.OracleDriveroracle.jdbc.driver.T4CConnection@28d51032

上述代码DriverManager同时连接oracle和mysql,换句话说,DriverManager同时管理着oracle和mysql两个驱动。那我们会产生疑问DriverManager到底是如果多个管理驱动的,怎么样根据我们的连接配置信息(url,密码...)获取到对应的连接?

驱动的管理或者说记录是封装成DriverInfo后放到DriverInfoCopyOnWriteArrayList,可以看做是一个线程安全的ArrayList。

private final static CopyOnWriteArrayList
registeredDrivers = new CopyOnWriteArrayList
();

当我们要获取连接的时候,再遍历registeredDrivers这个列表,然后使用列表中的驱动尝试连接,当获取到连接以后就停止遍历,然后返回connection

DriverManager的核心连接代码

private static Connection getConnection(        String url, java.util.Properties info, Class
caller) throws SQLException { // 省略。。。 println("DriverManager.getConnection(\"" + url + "\")"); SQLException reason = null; // 遍历驱动注册列表 for(DriverInfo aDriver : registeredDrivers) { // 判断是否能使用该驱动 if(isDriverAllowed(aDriver.driver, callerCL)) { try { println(" trying " + aDriver.driver.getClass().getName()); // 尝试连接 /** * 其实java.sql.Driver接口定义了一个方法判断驱动能不能接受url的连接, * boolean acceptsURL(String url) throws SQLException; * 这里其实先使下面代码进行判断 * if (!aDriver.driver.acceptsURL(url)) { * continue; * } * 但是没有使用上面代码进行判断,我猜可能的原因是: * 1、java官方并不要求实现acceptsURL()方法,我们平常 * 使用也很早用到这个方法。 * 2、存在一种这样的情况:某个数据库厂商协议进行升级 * 了,但是为了兼容旧的协议还是允许连接, * acceptsURL(旧协议的url)方法,返回false, * 起到一个提示的作用。 */ Connection con = aDriver.driver.connect(url, info); if (con != null) { // Success! println("getConnection returning " + aDriver.driver.getClass().getName()); // 没有报异常并且 connection 不为空,则返回connection return (con); } } catch (SQLException ex) { if (reason == null) { reason = ex; } } } else { println(" skipping: " + aDriver.getClass().getName()); } } // 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"); }}

转载于:https://my.oschina.net/hgp/blog/1456983

你可能感兴趣的文章
福利!给所有需要找工作的小伙伴分享让我印象深刻的的开发面试题(第二部分),朋友们收好哦...
查看>>
React 折腾记 - (5) 记录用React开发项目过程遇到的问题(Webpack4/React16/antd等)
查看>>
Angular 6 + 折腾记 :(11) 写一个挺不靠谱的多少秒/分/时/天前的管道
查看>>
掘金翻译计划周报 — 2018 年 9 月第 2 期
查看>>
整合登录界面与管理系统
查看>>
PyCon2018 回顾 (Part 1)
查看>>
vuex
查看>>
平时自己项目中用到的 CSS
查看>>
微信小程序5月带给我们的惊喜
查看>>
如何实现类似易企秀的可视化 H5 编辑器?
查看>>
[译] 游戏即服务的五条建议,提升游戏变现能力
查看>>
数据结构:链表
查看>>
gitlab迁移到docker并升级大版本到10.1.1和汉化
查看>>
多线程知识梳理(2) synchronized 三部曲之基本使用
查看>>
Xcode9 自动上传Fir
查看>>
JavaScript异步流程控制的前世今生
查看>>
通过static关键词来实现late static binding(静态调用绑定)
查看>>
Android小知识-OkHttp的两种请求方式
查看>>
阿里巴巴前端工程师一面二面三面终面面经总结
查看>>
Python正则表达式初识(七)
查看>>