美文网首页程序员首页投稿(暂停使用,暂停投稿)技术干货
jdbc详解:2、DriverManager管理多个数据库驱动

jdbc详解:2、DriverManager管理多个数据库驱动

作者: 白痴糊涂人 | 来源:发表于2017-07-18 16:39 被阅读488次

    前一篇地址:jdbc详解:1、创建数据库connection连接

    先上代码

        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<Driver> 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.Driver
    
    getConnection returning com.mysql.jdbc.Driver
    com.mysql.jdbc.JDBC4Connection@72d8c235
    ------加载的diver--------
    com.mysql.jdbc.Driver
    com.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<String>() {
                    public String run() {
                        return System.getProperty("jdbc.drivers");
                    }
                });
            } catch (Exception ex) {
                drivers = null;
            }
            
    
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    
                    // 扫描 java.sql.Driver的实现类,并加载
                    // 加载就按照前一篇文章一样进行驱动注册
                    ServiceLoader<Driver> 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.Driver
    
    getConnection returning com.mysql.jdbc.Driver
    com.mysql.jdbc.JDBC4Connection@22b3428e
    DriverManager.getConnection("jdbc:oracle:thin:@10.211.55.6:1521:ORCL")
        trying com.mysql.jdbc.Driver
        trying com.mysql.fabric.jdbc.FabricMySQLDriver
        trying oracle.jdbc.OracleDriver
    getConnection returning oracle.jdbc.OracleDriver
    oracle.jdbc.driver.T4CConnection@28d51032
    
    

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

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

    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>();
    

    当我们要获取连接的时候,再遍历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");
        }
    }
    
    

    相关文章

      网友评论

        本文标题:jdbc详解:2、DriverManager管理多个数据库驱动

        本文链接:https://www.haomeiwen.com/subject/uiehkxtx.html