深入解析JDBC源码
作者:赖皮小王子 | 来源:互联网 | 2024-12-25 19:59
本文详细探讨了JDBC(Java数据库连接)的内部机制,重点分析其作为服务提供者接口(SPI)框架的应用。通过类图和代码示例,展示了JDBC如何注册驱动程序、建立数据库连接以及执行SQL查询的过程。
### JDBC概述 JDBC是Java应用程序与关系型数据库进行交互的标准API。它遵循服务提供者接口(SPI)模式,使得不同数据库厂商可以为JDBC接口提供具体实现。 #### 类图 JDBC的核心类和接口包括`DriverManager`、`Driver`、`Connection`、`Statement`和`ResultSet`等。这些类和接口共同构成了JDBC的桥梁设计模式,将用户端的操作与数据库端的具体实现分离。 #### 示例代码 以下是一个简单的JDBC代码示例,展示了如何注册驱动程序、建立连接、执行查询并处理结果: ```java public void baseTest() throws SQLException, ClassNotFoundException { // 设置日志输出 DriverManager.setLogWriter(new PrintWriter(System.out)); // 建立连接 String url = "jdbc:mysql://127.0.0.1:3306/jdbc"; String user = "root"; String password = "123"; Connection cOnn= DriverManager.getConnection(url, user, password); // 创建语句 Statement st = conn.createStatement(); // 执行查询 ResultSet rs = st.executeQuery("select * from user"); // 处理结果 while (rs.next()) { System.out.println(rs.getObject(1) + "\t" + rs.getObject(2) + "\t" + rs.getObject(3) + "\t" + rs.getObject(4)); } // 释放资源 rs.close(); st.close(); conn.close(); } ``` ### 驱动注册与连接获取 在初始化时,`loadInitialDrivers()`方法会读取系统属性`jdbc.drivers`,并加载相应的驱动程序。此外,它还会使用`ServiceLoader`查找并加载META-INF/services目录下描述的实现了`Driver`接口的驱动类。 ```java private static void loadInitialDrivers() { String drivers = AccessController.doPrivileged(new PrivilegedAction() { public String run() { return System.getProperty("jdbc.drivers"); } }); if (drivers == null || drivers.isEmpty()) { return; } String[] driversList = drivers.split(":"); for (String driver : driversList) { try { Class.forName(driver, true, ClassLoader.getSystemClassLoader()); } catch (Exception ex) { // 处理异常 } } } ``` 如果JAR文件中没有在META-INF/services中描述驱动程序,则需要手动注册驱动。通常情况下,调用`Class.forName()`会自动触发驱动程序的注册。 ```java public static synchronized void registerDriver(Driver driver) throws SQLException { if (driver != null) { registeredDrivers.addIfAbsent(new DriverInfo(driver)); } else { throw new NullPointerException(); } println("registerDriver: " + driver); } ``` ### 获取数据库连接 `DriverManager.getConnection()`方法会遍历已注册的驱动程序,尝试根据提供的URL建立连接。如果找到合适的驱动程序并成功连接,则返回`Connection`对象;否则抛出异常。 ```java private static Connection getConnection(String url, Properties info, Class> caller) throws SQLException { ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; if (url == null) { throw new SQLException("The url cannot be null", "08001"); } for (DriverInfo aDriver : registeredDrivers) { if (isDriverAllowed(aDriver.driver, callerCL)) { try { Connection con = aDriver.driver.connect(url, info); if (con != null) { return con; } } catch (SQLException ex) { // 记录异常 } } } throw new SQLException("No suitable driver found for " + url, "08001"); } ``` ### MySQL连接示例 MySQL驱动程序通过解析URL来确定连接类型,并返回具体的`Connection`对象。 ```java public Connection connect(String url, Properties info) throws SQLException { if (url != null) { if (url.startsWith("jdbc:mysql:loadbalance://")) { return connectLoadBalanced(url, info); } if (url.startsWith("jdbc:mysql:replication://")) { return connectReplicationConnection(url, info); } } Properties props = parseURL(url, info); if (props == null) { return null; } try { com.mysql.jdbc.Connection cOnn= ConnectionImpl.getInstance(host(props), port(props), props, database(props), url); return conn; } catch (SQLException e) { throw e; } catch (Exception e) { throw SQLError.createSQLException(e.getMessage(), "08001", null); } } ``` ### 设计模式 JDBC广泛使用了桥梁设计模式和工厂方法设计模式。桥梁设计模式通过`DriverManager`和`Driver`桥接用户端和数据库端,而工厂方法设计模式则由具体的`Driver`生成`Connection`对象。
推荐阅读
本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ...
[详细]
蜡笔小新 2024-12-28 10:51:55
Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ...
[详细]
蜡笔小新 2024-12-28 08:54:34
1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ...
[详细]
蜡笔小新 2024-12-27 19:32:17
本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ...
[详细]
蜡笔小新 2024-12-27 16:11:49
本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ...
[详细]
蜡笔小新 2024-12-27 16:01:25
本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ...
[详细]
蜡笔小新 2024-12-27 15:06:12
本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ...
[详细]
蜡笔小新 2024-12-27 15:04:09
本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ...
[详细]
蜡笔小新 2024-12-27 10:28:40
在 Swift 编程中,遇到错误提示“一元运算符 '!' 不能应用于 '()' 类型的操作数”,通常是因为尝试对没有返回值的方法或函数应用逻辑非运算符。本文将详细解释该错误的原因,并提供解决方案。 ...
[详细]
蜡笔小新 2024-12-26 18:42:22
本文详细介绍了 Apache Jena 库中的 Txn.executeWrite 方法,通过多个实际代码示例展示了其在不同场景下的应用,帮助开发者更好地理解和使用该方法。 ...
[详细]
蜡笔小新 2024-12-26 17:55:52
本文详细介绍了中央电视台电影频道的节目预告,并通过专业工具分析了其加载方式,确保用户能够获取最准确的电视节目信息。 ...
[详细]
蜡笔小新 2024-12-25 21:01:14
本文探讨了如何在编程中正确处理包含空数组的 JSON 对象,提供了详细的代码示例和解决方案。 ...
[详细]
蜡笔小新 2024-12-26 16:33:40
本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ...
[详细]
蜡笔小新 2024-12-26 16:06:09
本文详细介绍了 Java 中 org.apache.xmlbeans.SchemaType 类的 getBaseEnumType() 方法,提供了多个代码示例,并解释了其在不同场景下的使用方法。 ...
[详细]
蜡笔小新 2024-12-26 11:46:55
本文详细介绍了Java泛型的概念及其在JDK 5中的应用,通过具体代码示例解释了泛型的引入、作用和优势。同时,探讨了泛型类、泛型方法和泛型接口的实现,并深入讲解了通配符的使用。 ...
[详细]
蜡笔小新 2024-12-26 11:15:56