zoukankan      html  css  js  c++  java
  • JDBC(二)、注册驱动三种实现原理

    类的加载时机

    • new对象
    • 加载子类
    • 通过类中的静态成员
    • 通过反射

    使用new 对象的方式加载类的不足:

    • 属于编译器加载,如果编译期键4间该类不存在,则直接报编译错误,强依赖
    • 导致Driver对象创建了两遍,效率较低。

    rs.next()

    指向下一行

    rs.getObject

    获取单元格

    创建和释放的顺序相反

    最后创建的先释放

    为什么需要释放

    JDBC实际上是Socket连接,开端口号,占用系统的内存,个数是有限的

    关闭连接非常重要,如果上线时不关闭连接,表现非常明显
    尽量晚的建立连接,尽量早的释放连接,减少占用时间。

    三种方法

    • 1.System.setProperty
    System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver:oracle.jdbc.driver.OracleDriver");
    
    
    • 2.registerDriver
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
    
    • 3.Class.forName
        Class.forName("com.mysql.jdbc.Driver");
    

    前两种方法分析

    loadInitialDrivers源码

    原理loadInitialDrivers方法会取出属性判断

        private static void loadInitialDrivers() {
            String drivers;
            try {
                drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
                    public String run() {
                        return System.getProperty("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.
            // ServiceLoader.load() replaces the sun.misc.Providers()
    
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
    
                    ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                    Iterator<Driver> driversIterator = loadedDrivers.iterator();
    
                    /* Load these drivers, so that they can be instantiated.
                     * It may be the case that the driver class may not be there
                     * i.e. there may be a packaged driver with the service class
                     * as implementation of java.sql.Driver but the actual class
                     * may be missing. In that case a java.util.ServiceConfigurationError
                     * will be thrown at runtime by the VM trying to locate
                     * and load the service.
                     *
                     * Adding a try catch block to catch those runtime errors
                     * if driver not available in classpath but it's
                     * packaged as service and that service is there in classpath.
                     */
                    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;
            }
            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);
                }
            }
        }
    

    registerDriver

        public static synchronized void registerDriver(java.sql.Driver driver)
            throws SQLException {
    
            registerDriver(driver, null);
        }
        
        
        public static synchronized void registerDriver(java.sql.Driver driver,
                DriverAction da)
            throws SQLException {
    
            /* Register the driver if it has not already been added to our list */
            if(driver != null) {
                registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
            } else {
                // This is for compatibility with the original DriverManager
                throw new NullPointerException();
            }
    
            println("registerDriver: " + driver);
    
        }    
    
    
    

    deregisterDriver(Driver driver) 卸载驱动源码

        @CallerSensitive
        public static synchronized void deregisterDriver(Driver driver)
            throws SQLException {
            if (driver == null) {
                return;
            }
    
            SecurityManager sec = System.getSecurityManager();
            if (sec != null) {
                sec.checkPermission(DEREGISTER_DRIVER_PERMISSION);
            }
    
            println("DriverManager.deregisterDriver: " + driver);
    
            DriverInfo aDriver = new DriverInfo(driver, null);
            if(registeredDrivers.contains(aDriver)) {
                if (isDriverAllowed(driver, Reflection.getCallerClass())) {
                    DriverInfo di = registeredDrivers.get(registeredDrivers.indexOf(aDriver));
                     // If a DriverAction was specified, Call it to notify the
                     // driver that it has been deregistered
                     if(di.action() != null) {
                         di.action().deregister();
                     }
                     registeredDrivers.remove(aDriver);
                } else {
                    // If the caller does not have permission to load the driver then
                    // throw a SecurityException.
                    throw new SecurityException();
                }
            } else {
                println("    couldn't find driver to unload");
            }
        }
    

    第三种实现

    static块中将驱动注册进ManagerDriver,所以前两种方式实际上

    package com.mysql.jdbc;
    
    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    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!");
            }
        }
    }
    
    

    其他:

    driverinfo封装每一个传入的driver的信息

    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers
    
    
     registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
     
    如果没有就添加进CopyOnWriteArrayList,
    

    CopyOnWriteArrayList的特点:

    • 实现了List接口
    • 内部持有一个ReentrantLock lock = new ReentrantLock();
    • 底层是用volatile transient声明的数组 array
    • 读写分离,写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array

    写时复制:
    https://blog.csdn.net/weixin_39554266/article/details/82835478

    三种比较

    • 后两种都是字符串,反射得到类,去掉jar包也能通过编译。
    • 第一种,new对象依赖于jar包,不能通过编译。(更换数据库需要改代码)
  • 相关阅读:
    AMBA总线介绍
    placeholder不显示的解决办法(支持ie8以上)
    通过新浪微博API获取数据
    PHP时间运算
    PHP队列
    stream_context_create()
    http_build_query()
    shuffle()
    session_id()
    session_name()
  • 原文地址:https://www.cnblogs.com/biturd/p/12623150.html
Copyright © 2011-2022 走看看