JDBC源码分析

1.传统的jdbc 步骤:

Connection connection=null;
        PreparedStatement preparedStatement=null;
        ResultSet resultSet=null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/myshool?characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong","root","root");
            String sql="select * from student where name= ? ";
            preparedStatement=connection.prepareStatement(sql);
            preparedStatement.setString(1,"小明");
            resultSet=preparedStatement.executeQuery();
            while (resultSet.next()){
                System.out.println(resultSet.getString("id")+" " +resultSet.getString("name"));
            }


        }
        catch (ClassNotFoundException e) {
            e.printStackTrace();
       } catch (SQLException e) {
            e.printStackTrace();
        }

这里检出一下步骤:建表,创建连接,操作数据库,等一般模式。

2。源码分析:

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

在Class.forName加载完驱动类后,开始执行静态代码块时,会new一个Driver,并调用DriverManager的registerDriver把Driver给注册到自己的驱动程序管理器(DriverManager)中去。

  •  

问题1.为啥使用DriverMangangsger?????

  • Classloder.loaderClass(String name)

    其实该方法内部调用的是:Classloder. loadClass(name, false)

    方法:Classloder. loadClass(String name, boolean resolve)

        1:参数name代表类的全限定类名

        2:参数resolve代表是否解析,resolve为true是解析该类

  • Class.forName(String name)

    其实该方法内部调用的是:Class.forName(className, true, ClassLoader.getClassLoader(caller))

    方法:Class.forName0(String name, boolean initialize, ClassLoader loader)

      参数name代表全限定类名

      参数initialize表示是否初始化该类,为true是初始化该类

      参数loader 对应的类加载器

Class.forName得到的class是已经初始化完成的

    Classloder.loaderClass得到的class是没有初始化的

river接口是每个数据库驱动都必须继承的接口

public class DriverManager {

    //已经注册的驱动列表
    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
    private static volatile int loginTimeout = 0;
    private static volatile java.io.PrintWriter logWriter = null;
    private static volatile java.io.PrintStream logStream = null;
    // Used in println() to synchronize logWriter
    private final static  Object logSync = new Object();
    //阻止被初始化,DriverManager里面都是静态的方法。
    private DriverManager(){}
    //初始化加载驱动,其中用到了ServiceLoader机制
    static {
        //初始化加载驱动
        loadInitialDrivers();
        //打印日志
        println("JDBC DriverManager initialized");
    }
    /*因为源代码过长,这里我们只讲重要的一些方法*/

    //初始化加载驱动
    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;
        }
        //这里涉及到一个ServiceLoader概念。上面我推荐了一篇文章,想了解的可以去看看。通过ServiceLoader去加载所有的driver。
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                //通过ServiceLoader.load()方法加载所有驱动
                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();

                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();
                    }
                } catch(Throwable t) {

                }
                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);
            }
        }
    }

    //3个获取connection方法,对外提供的方法。
    @CallerSensitive
    public static Connection getConnection(String url, java.util.Properties info) throws SQLException {

        return (getConnection(url, info, Reflection.getCallerClass()));
    }   
    //这个方法中可以看到,properties中至少配置参数其实就是user和password
    @CallerSensitive
    public static Connection getConnection(String url,
        String user, String password) throws SQLException {
        java.util.Properties info = new java.util.Properties();

        if (user != null) {
            info.put("user", user);
        }
        if (password != null) {
            info.put("password", password);
        }

        return (getConnection(url, info, Reflection.getCallerClass()));
    }

    @CallerSensitive
    public static Connection getConnection(String url)
        throws SQLException {

        java.util.Properties info = new java.util.Properties();
        return (getConnection(url, info, Reflection.getCallerClass()));
    }
     // 内部真正工作的方法(私有)
    private static Connection getConnection(
        String url, java.util.Properties info, Class<?> caller) throws SQLException {
        //检查callerCL是否为空,如果为空则通过Thread.currentThread().getContextClassLoader()去加载
        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
        synchronized(DriverManager.class) {
            // synchronize loading of the correct classloader.
            if (callerCL == null) {
                callerCL = Thread.currentThread().getContextClassLoader();
            }
        }
        //这里判断url
        if(url == null) {
            throw new SQLException("The url cannot be null", "08001");
        }

        println("DriverManager.getConnection(\"" + url + "\")");
        SQLException reason = null;
        //遍历registeredDrivers去获得正确的connection
        for(DriverInfo aDriver : registeredDrivers) {
            // 如果callerCL不允许读取驱动,就会跳过。
            if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    println("    trying " + aDriver.driver.getClass().getName());
                    //真正的获取connection的方法,其实还是通过driver接口中的connect方法。
                    Connection con = aDriver.driver.connect(url, info);
                    if (con != null) {
                        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");
    }

    //通过url获取driver。
    @CallerSensitive
    public static Driver getDriver(String url)
        throws SQLException {

        println("DriverManager.getDriver(\"" + url + "\")");

        Class<?> callerClass = Reflection.getCallerClass();

        // 通过遍历registeredDrivers中每个驱动
        for (DriverInfo aDriver : registeredDrivers) {
            // acceptsURL()方法判断url是否符合driver
            if(isDriverAllowed(aDriver.driver, callerClass)) {
                try {
                    if(aDriver.driver.acceptsURL(url)) {
                        println("getDriver returning " + aDriver.driver.getClass().getName());
                    return (aDriver.driver);
                    }

                } catch(SQLException sqe) {

                }
            } else {
                println("    skipping: " + aDriver.driver.getClass().getName());
            }

        }

        println("getDriver: no suitable driver");
        throw new SQLException("No suitable driver", "08001");
    }

    //注册驱动的方法
    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 {
        //判断driver是否已经被加载到registeredDrivers,没有就加进去
        if(driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
        } else {
            throw new NullPointerException();
        }
        println("registerDriver: " + 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(di.action() != null) {
                     di.action().deregister();
                 }
                 //通过remove()注销。
                 registeredDrivers.remove(aDriver);
            } else {
                throw new SecurityException();
            }
        } else {
            println("    couldn't find driver to unload");
        }
    }   
}

2.preparedstatement 为什么statement 好?
statement和preparedStatement的作用是一样的,都是用来执行sql。

1.代码的可读性和可维护性. 
虽然用PreparedStatement来代替Statement会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说.都比直接用Statement的代码高很多档次: 
stmt.executeUpdate(“insert into tb_name (col1,col2,col2,col4) values (‘”+var1+”’,’”+var2+”’,”+var3+”,’”+var4+”’)”);//stmt是Statement对象实例

perstmt = con.prepareStatement(“insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)”); 
perstmt.setString(1,var1); 
perstmt.setString(2,var2); 
perstmt.setString(3,var3); 
perstmt.setString(4,var4); 
perstmt.executeUpdate(); //prestmt是 PreparedStatement 对象实例

2.PreparedStatement尽最大可能提高性能. 

3.最重要的一点是极大地提高了安全性.

由此可见:开发的时候尽量用preparedStatement,少用statement。 

参考博文:

https://www.cnblogs.com/itgaofei/p/9229540.html

发布了550 篇原创文章 · 获赞 10 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/xiamaocheng/article/details/104412631
今日推荐