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的。
- spring jdbc 源码 分析
- jdbc 驱动源码分析
- JDBC源码分析
- JDBC源码分析
- JDBC源码分析(1)
- spring 源码分析 spring jdbc
- JAVA JDBC(MySQL)驱动源码分析(一)
- JAVA JDBC(MySQL)驱动源码分析(二)
- JAVA JDBC(MySQL)驱动源码分析(三)
- JAVA JDBC(MySQL)驱动源码分析(四)
- JAVA JDBC(MySQL)驱动源码分析(二)
- JAVA JDBC(MySQL)驱动源码分析
- PostgreSQL JDBC 源码分析之fetchSize
- JAVA JDBC(MySQL)驱动源码分析
- phoenix jdbc driver查询源码分析
- 基于PostgreSQL链接JDBC源码分析
- tomcat-jdbc Pool 源码实现简单分析
- JDBC源码分析&桥接模式
- log日志新玩意Logger
- 注释转换
- SSM框架重构达内NETCTOSS项目——(1)开发准备
- windows平台使用sublime编辑器编译C代码,亲测可用
- 5-3 编写程序
- JDBC源码分析
- 5-4 设计一个Dog类
- Go初体验
- NVIDIA Jetson TK1开发板上手
- Java编程入门程序实践
- 大数据平台搭建(hadoop+spark)
- 网络问题导致Rstudio正确安装包
- 5-5 设计一个表示拥护的User类
- 文章标题