- 核心概念:JDBC 和 Oracle 驱动
- 环境准备:下载必要的软件和驱动
- 核心步骤:Java 连接 Oracle 数据库的详细代码
- 最佳实践:使用连接池和
try-with-resources - 完整示例:一个可运行的完整项目
- 常见问题与解决方案
核心概念:JDBC 和 Oracle 驱动
JDBC (Java Database Connectivity)
JDBC 是 Java 提供的一套标准 API,用于执行 SQL 语句,它定义了如何从 Java 应用程序连接到各种数据库、执行查询、获取结果等,你可以把它想象成 Java 和数据库之间的“通用翻译官”。

Oracle JDBC 驱动
JDBC 只是一个标准,而 Oracle 驱动是实现这个标准的“具体翻译官”,Oracle 提供了官方的 JDBC 驱动程序(也称为 JDBC Driver 或 JDBC Thin Driver),它负责将 Java 的 JDBC 调用转换成 Oracle 数据库能够理解的协议。
Oracle 驱动主要有两种:
- Thin Driver (瘦驱动):这是最常用的一种,它是一个纯 Java 驱动,不依赖 Oracle 客户端库,可以直接通过网络连接到数据库服务器,对于大多数应用来说,这是首选。
- OCI (Oracle Call Interface) Driver (OCI 驱动):它需要本地库(
oci.dll或liboci.so),因此依赖于 Oracle 客户端安装,它通常用于需要高级功能(如高级数据类型、更高性能)的场景,但在配置上比 Thin 驱动复杂。
我们这里主要讲解最常用、最方便的 Thin Driver。
环境准备
在开始编码之前,你需要准备好以下三样东西:

a) 安装并启动 Oracle 数据库
确保你有一台可以访问的 Oracle 数据库服务器(本地安装的 Oracle 11g, 12c, 19c, 21c 等),并且数据库服务已经启动,你需要知道以下连接信息:
- 主机名:
localhost(如果是本地) 或数据库服务器的 IP 地址。 - 端口:默认的 Oracle 端口是
1521。 - SID (System Identifier) 或 Service Name:
- SID:是数据库实例的唯一标识,是较老的概念,格式如
ORCL。 - Service Name:是 Oracle 推荐的新方式,格式可以更灵活,如
ORCLCDB。 - 你需要根据你的数据库配置来确定使用哪一个,连接字符串的格式会略有不同。
- SID:是数据库实例的唯一标识,是较老的概念,格式如
b) 下载 Oracle JDBC 驱动 (JAR 文件)
你需要从 Oracle 官网下载 JDBC 驱动的 JAR 包。
- 访问 Oracle 官方下载页面:Oracle JDBC Drivers
- 根据你的数据库版本选择合适的驱动,新版本的驱动可以兼容旧版本的数据库。
- 下载文件通常是一个 ZIP 压缩包,
ojdbc8.jar(适用于 Java 8) 或ojdbc11.jar(适用于 Java 11+)。 - 关键一步:将下载的
ojdbcX.jar文件添加到你的 Java 项目的 Classpath 中。- 如果你使用 Maven:这是最推荐的方式,可以避免手动管理 JAR 文件。
- 如果你使用 IDE (如 IntelliJ IDEA 或 Eclipse):右键项目 -> Build Path / Project Structure -> Libraries -> Add External JARs...,然后选择你下载的
ojdbcX.jar。 - 如果你使用命令行编译:使用
-cp参数指定 JAR 文件路径,java -cp ".;ojdbc8.jar" YourMainClass(Windows) 或java -cp ".:ojdbc8.jar" YourMainClass(Linux/macOS)。
c) 创建数据库用户和表
为了方便测试,我们可以在 Oracle 数据库中创建一个简单的用户和一张表。
-- 连接到你的数据库(使用 SQL*Plus 或其他工具)
-- 以 sysdba 身份登录
-- conn / as sysdba
-- 创建一个新用户(如果不存在)
CREATE USER java_user IDENTIFIED BY password123;
-- 授予该用户基本的数据库权限
GRANT CONNECT, RESOURCE TO java_user;
-- 切换到新用户
-- conn java_user/password123
-- 创建一张测试表
CREATE TABLE employees (
id NUMBER PRIMARY KEY,
name VARCHAR2(100) NOT NULL,
email VARCHAR2(100),
hire_date DATE
);
-- 插入一些测试数据
INSERT INTO employees (id, name, email, hire_date) VALUES (1, '张三', 'zhangsan@example.com', TO_DATE('2025-01-15', 'YYYY-MM-DD'));
INSERT INTO employees (id, name, email, hire_date) VALUES (2, '李四', 'lisi@example.com', TO_DATE('2025-05-20', 'YYYY-MM-DD'));
COMMIT;
核心步骤:Java 连接代码
以下是使用 Java 连接 Oracle 数据库并执行查询的标准步骤。

步骤 1:加载驱动
虽然在新版本的 JDBC (JDBC 4.0+) 中,这一步通常是可选的(驱动会自动注册),但显式加载仍然是一个好习惯。
Class.forName("oracle.jdbc.OracleDriver");
步骤 2:建立连接
使用 DriverManager.getConnection() 方法,并提供正确的连接 URL、用户名和密码。
连接 URL 格式:
- 使用 SID:
jdbc:oracle:thin:@<hostname>:<port>:<SID>jdbc:oracle:thin:@localhost:1521:ORCL - 使用 Service Name (推荐):
jdbc:oracle:thin:@//<hostname>:<port>/<service_name>jdbc:oracle:thin:@//localhost:1521/ORCLCDB
String dbUrl = "jdbc:oracle:thin:@//localhost:1521/ORCLCDB"; String dbUser = "java_user"; String dbPassword = "password123"; Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPassword);
步骤 3:创建 Statement
通过 Connection 对象创建一个 Statement 或 PreparedStatement 对象,用于执行 SQL 语句。强烈推荐使用 PreparedStatement,因为它可以防止 SQL 注入攻击,并且性能更好。
String sql = "SELECT id, name, email, hire_date FROM employees WHERE id = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, 1); // 设置第一个参数为 id=1
步骤 4:执行查询
使用 executeQuery() 方法执行查询,返回一个 ResultSet 对象。
ResultSet rs = pstmt.executeQuery();
步骤 5:处理结果集
遍历 ResultSet 对象,获取查询结果。
while (rs.next()) {
// 通过列名获取数据,更安全、可读性更好
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
Date hireDate = rs.getDate("hire_date");
System.out.println("ID: " + id + ", Name: " + name + ", Email: " + email + ", Hire Date: " + hireDate);
}
步骤 6:关闭资源
非常重要! 在使用完 ResultSet、Statement 和 Connection 后,必须将它们关闭,以释放数据库资源,顺序是:先关闭 ResultSet,再关闭 Statement,最后关闭 Connection。
rs.close(); pstmt.close(); conn.close();
最佳实践:使用连接池和 try-with-resources
直接使用 DriverManager 获取连接在每次请求时都会创建一个新的物理连接,性能很差,在高并发应用中,必须使用连接池。
连接池
连接池(如 HikariCP, DBCP, C3P0)预先创建一组数据库连接,并将它们放入池中,当应用需要连接时,从池中获取一个,用完后归还给池,而不是销毁,这极大地提高了性能。
HikariCP 是目前性能最好的连接池,是 Spring Boot 的默认选择。
try-with-resources 语句
从 Java 7 开始,引入了 try-with-resources 语句,它可以自动实现 AutoCloseable 接口的资源(如 Connection, Statement, ResultSet)在 try 块执行完毕后自动关闭,即使发生异常也能保证关闭,从而避免了资源泄漏。
结合连接池和 try-with-resources 的现代写法:
// 1. 配置 HikariCP 连接池
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:oracle:thin:@//localhost:1521/ORCLCDB");
config.setUsername("java_user");
config.setPassword("password123");
// 其他优化配置...
config.setMaximumPoolSize(10);
HikariDataSource ds = new HikariDataSource(config);
// 2. 使用 try-with-resources 获取连接和执行操作
String sql = "SELECT id, name, email FROM employees";
try (Connection conn = ds.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
System.out.println("Name: " + rs.getString("name") + ", Email: " + rs.getString("email"));
}
} catch (SQLException e) {
e.printStackTrace();
} // conn, pstmt, rs 会在这里自动关闭
注意:HikariDataSource 本身不需要在每次使用后关闭,它通常作为应用的全局单例存在,在应用关闭时再销毁。
完整示例 (Maven 项目)
这是一个使用 Maven 和 HikariCP 的完整、可运行的示例。
a) pom.xml
创建一个 Maven 项目,并添加以下依赖。
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>oracle-java-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Oracle JDBC Driver -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<version>21.9.0.0</version>
</dependency>
<!-- HikariCP Connection Pool -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>
</dependencies>
</project>
b) OracleJdbcDemo.java
在 src/main/java 目录下创建这个类。
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Date;
public class OracleJdbcDemo {
// 数据库连接信息 - 最好放在配置文件中
private static final String DB_URL = "jdbc:oracle:thin:@//localhost:1521/ORCLCDB";
private static final String DB_USER = "java_user";
private static final String DB_PASSWORD = "password123";
public static void main(String[] args) {
// 1. 创建 HikariCP 连接池
HikariConfig config = new HikariConfig();
config.setJdbcUrl(DB_URL);
config.setUsername(DB_USER);
config.setPassword(DB_PASSWORD);
// 性能优化配置
config.setMaximumPoolSize(10);
config.setMinimumIdle(5);
config.setConnectionTimeout(30000); // 30 seconds
config.setIdleTimeout(600000); // 10 minutes
config.setMaxLifetime(1800000); // 30 minutes
HikariDataSource dataSource = new HikariDataSource(config);
// 2. 使用 try-with-resources 获取连接并执行查询
// 查询所有员工
queryAllEmployees(dataSource);
// 查询特定ID的员工
queryEmployeeById(dataSource, 1);
// 3. 在应用关闭时关闭数据源
dataSource.close();
}
public static void queryAllEmployees(HikariDataSource dataSource) {
String sql = "SELECT id, name, email, hire_date FROM employees";
System.out.println("--- Querying All Employees ---");
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
Date hireDate = rs.getDate("hire_date");
System.out.printf("ID: %d, Name: %s, Email: %s, Hire Date: %s%n", id, name, email, hireDate);
}
} catch (SQLException e) {
System.err.println("Error querying employees: " + e.getMessage());
}
}
public static void queryEmployeeById(HikariDataSource dataSource, int employeeId) {
String sql = "SELECT id, name, email FROM employees WHERE id = ?";
System.out.printf("--- Querying Employee with ID: %d ---%n", employeeId);
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, employeeId);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
System.out.printf("Found Employee -> ID: %d, Name: %s, Email: %s%n", id, name, email);
} else {
System.out.println("No employee found with ID: " + employeeId);
}
}
} catch (SQLException e) {
System.err.println("Error querying employee by ID: " + e.getMessage());
}
}
}
常见问题与解决方案
问题 1:java.lang.ClassNotFoundException: oracle.jdbc.OracleDriver
原因:JDBC 驱动的 JAR 文件没有被添加到 Classpath 中。
解决方案:检查你的构建工具(Maven/Gradle)或 IDE 是否正确引入了 ojdbcX.jar。
问题 2:java.sql.SQLException: No suitable driver found for jdbc:oracle:thin:@...
原因:
- 驱动未加载(虽然少见)。
- JDBC URL 格式错误(
SID和Service Name混用,或拼写错误)。 解决方案:仔细检查 JDBC URL 的格式是否与你的数据库配置匹配。
问题 3:java.sql.SQLException: Io 异常: The Network Adapter could not establish the connection
原因:网络问题,Java 应用无法连接到指定的主机和端口。 解决方案:
- 检查主机名和端口号是否正确。
- 确保数据库监听器正在运行,在 Oracle 服务器上,可以使用
lsnrctl status命令检查。 - 检查防火墙是否阻止了
1521端口。
问题 4:java.sql.SQLException: ORA-01017: invalid username/password; logon denied
原因:用户名或密码错误。 解决方案:确认你使用的用户名和密码是正确的,并且该用户有权限连接到数据库。
问题 5:java.sql.SQLException: ORA-00942: table or view does not exist
原因:SQL 语句中表名或视图名拼写错误,或者当前用户没有访问该表的权限。
解决方案:检查表名拼写是否正确,并确认用户是否有 SELECT 权限。
