JDBC源码分析

来源:互联网 发布:淘宝小样正品店 编辑:程序博客网 时间:2024/06/05 16:57

上一篇文章讲了JDBC的使用。其中涉及到了几个类:Driver、DriverManager、Connection、Statement、ResultSet等。这些都是来自 package java.sql 包下的类。下面让我们来看源码一起了解这些包具体的用法。

1、Driver 驱动接口

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

public interface Driver {    //获取Connection 方法。数据库的url,及info至少得包含user,password key    Connection connect(String url, java.util.Properties info)        throws SQLException;    //判断是否是一个正确的url字符串。    boolean acceptsURL(String url) throws SQLException;    //得到驱动的属性(user,password,port等)。    DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info) throws SQLException;    //得到主要版本    int getMajorVersion();    //得到次要版本    int getMinorVersion();    //判断是否是一个正确的driver    boolean jdbcCompliant();    //------------------------- JDBC 4.1 -----------------------------------    //返回父日志    public Logger getParentLogger() throws SQLFeatureNotSupportedException;}

2、DriverManager 驱动管理类

DriverManager管理一组 JDBC 驱动程序的基本服务。
初始化时有用到ServiceLoader机制,关于ServiceLoader,推荐看一篇博文 连接地址。
这也就是为什么可以直接用Class.forName(driver); 就可以完成加载驱动。

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

3、Connection 接口

代表与数据库的链接,并拥有创建SQL语句的方法,以完成基本的SQL操作,同时为数据库事务提供提交和回滚方法

public interface Connection  extends Wrapper, AutoCloseable {    //创建statement    Statement createStatement() throws SQLException;    //创建prepareStatement    PreparedStatement prepareStatement(String sql)        throws SQLException;    //创建CallableStatement    CallableStatement prepareCall(String sql) throws SQLException;    //转换sql为本机执行sql    String nativeSQL(String sql) throws SQLException;    //设置是否自动提交 状态    void setAutoCommit(boolean autoCommit) throws SQLException;    //判断是否是自动提交    boolean getAutoCommit() throws SQLException;    //提交    void commit() throws SQLException;    //回滚    void rollback() throws SQLException;    //关闭连接    void close() throws SQLException;    //判断是否关闭    boolean isClosed() throws SQLException;    ...//都是一些规范的接口,太多就不一一列举了。}

4、statement,PreparedStatement及CallableStatement 接口

statement和preparedStatement的作用是一样的,都是用来执行sql,区别是preparedStatement会进行sql语句的预编译,也可以动态拼接。因为会进行预编译,所以当用动态拼接的时候,会对传入的参数进行强制转换,所以会对参数进行校验,可以避免sql注入。开发的时候尽量用preparedStatement,少用statement。
CallableStatement 对象为所有的 DBMS 提供了一种以标准形式调用已储存过程的方法。

public interface PreparedStatement extends Statement {    //用于产生单个结果集的语句,例如 SELECT 语句    ResultSet executeQuery() throws SQLException;    //用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL(数据定义语言)语句    int executeUpdate() throws SQLException;    //设置空值,必须穿入type,不然可能报空指针异常    void setNull(int parameterIndex, int sqlType) throws SQLException;    ...(同理有很多set的方法)    //清空属性    void clearParameters() throws SQLException;    //用于执行返回多个结果集、多个更新计数或二者组合的语句    boolean execute() throws SQLException;    ...//都是一些规范的接口,太多就不一一列举了。}

5、ResultSet 结果集接口

结果集(ResultSet)是数据中查询结果返回的一种对象,可以说结果集是一个存储查询结果的对象,但是结果集并不仅仅具有存储的功能,他同时还具有操纵数据的功能,可能完成对数据的更新等

public interface ResultSet extends Wrapper, AutoCloseable {    //是否有下一个值    boolean next() throws SQLException;    //关闭    void close() throws SQLException;    //是否为空    boolean wasNull() throws SQLException;    //得到第几列的String类型数据    String getString(int columnIndex) throws SQLException;    boolean getBoolean(int columnIndex) throws SQLException;    ...(太多get方法不一一列举)    //得到列名为columnLabel的值    String getString(String columnLabel) throws SQLException;    //更新第几列为空(各种update方法)    void updateNull(int columnIndex) throws SQLException;    //插入(updateRow、deleteRow、refreshRow 等)    void insertRow() throws SQLException;}

看了上面这些源码的方法,再回头去看JDBC使用的步骤,你就应该能知道driver是如何加载,然后再获取connection,之后得到Statement,调用executeQuery()方法,再获的resultSet结果类,进行数据的遍历或处理。当然,这里源码有许多都是接口,也没有具体实现的内容。我下篇文件会讲解基于postgresql的连接jdbc的jar包源码来讲解具体PostgreSQL是如何实现JDBC的。

0 0
原创粉丝点击