热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入解析JDBC源码

本文详细探讨了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`对象。

推荐阅读
author-avatar
赖皮小王子
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有