杰瑞科技汇

Java如何连接Oracle数据库?

目录

  1. 准备工作
    • 安装 Oracle 数据库并创建测试用户和表
    • 下载 Oracle JDBC 驱动
  2. 核心概念:JDBC 驱动类型
    • OCI (Oracle Call Interface)
    • Thin Driver (纯 Java 驱动)
  3. 代码实现
    • 使用 ojdbc8.jar (JDBC 4.2 / Java 8+)
      • 传统方式 (Class.forName)
      • 现代方式 (自动加载)
      • 完整的 try-with-resources 示例 (推荐)
    • 使用 ojdbc11.jar (JDBC 4.3 / Java 11+)

      完整示例

      Java如何连接Oracle数据库?-图1
      (图片来源网络,侵删)
  4. 最佳实践
    • 使用连接池 (Connection Pooling)
      • 为什么需要连接池?
      • 使用 HikariCP (目前性能最好的连接池)
    • 使用 try-with-resources
    • 使用 PreparedStatement 防止 SQL 注入
    • 处理异常
  5. 常见问题与解决方案
    • ClassNotFoundExceptionNoClassDefFoundError
    • Invalid URL format
    • IO Error: The Network Adapter could not establish connection
    • ORA-01017: invalid username/password; logon denied

准备工作

a. 安装 Oracle 数据库并创建测试用户和表

确保你已经有一个可运行的 Oracle 数据库实例(如 Oracle Express Edition),以 syssystem 用户登录,创建一个测试用户和一张表。

-- 1. 创建用户 (请替换 'your_password' 为一个强密码)
CREATE USER java_user IDENTIFIED BY your_password;
-- 2. 授予用户权限
GRANT CONNECT, RESOURCE TO java_user;
-- 3. 切换到新创建的用户
CONN java_user/your_password@localhost:1521/XE  -- 注意:XE是OracleXE的默认服务名,根据你的实际情况修改
-- 4. 创建测试表
CREATE TABLE employees (
    id          NUMBER PRIMARY KEY,
    name        VARCHAR2(100),
    email       VARCHAR2(100),
    salary      NUMBER(10, 2)
);
-- 5. 插入一些测试数据
INSERT INTO employees (id, name, email, salary) VALUES (1, 'Alice', 'alice@example.com', 7000);
INSERT INTO employees (id, name, email, salary) VALUES (2, 'Bob', 'bob@example.com', 8000);
COMMIT;

b. 下载 Oracle JDBC 驱动

你需要从 Oracle 官网下载 JDBC 驱动,根据你的 Java 版本选择合适的版本:

  • 对于 Java 8 (JDBC 4.2): 下载 ojdbc8.jar
  • 对于 Java 11 及以上 (JDBC 4.3): 下载 ojdbc11.jar

下载地址: Oracle JDBC Drivers

下载后,将 .jar 文件添加到你的 Java 项目的类路径中,如果你使用的是 IDE(如 IntelliJ IDEA 或 Eclipse),可以直接将 JAR 文件添加到项目的 Libraries 中。

Java如何连接Oracle数据库?-图2
(图片来源网络,侵删)

核心概念:JDBC 驱动类型

Oracle 提供了两种主要的 JDBC 驱动:

a. OCI (Oracle Call Interface)

  • 特点: 它是一个本机库(如 Windows 下的 .dll 或 Linux 下的 .so 文件),依赖于 Oracle 客户端软件,它可以使用本机优化(如 OCI 网络协议)。
  • URL 格式: jdbc:oracle:oci:@<database_name>
  • 缺点: 部署复杂,需要在客户端机器上安装 Oracle 客户端,不适合跨平台部署。

b. Thin Driver (纯 Java 驱动)

  • 特点: 100% 用 Java 编写,不依赖任何本地库,它通过标准的 TCP/IP 套接字与数据库通信。
  • URL 格式: jdbc:oracle:thin:@<host>:<port>:<service_name_or_sid>
  • 优点: 部署简单,只需一个 JAR 文件,是 Web 应用和大多数场景下的首选。

本文将重点介绍 Thin Driver,因为它是最常用和最方便的。


代码实现

使用 ojdbc8.jar (Java 8+)

a. 传统方式 (不推荐,但为了知识完整性)

在 JDBC 4.0 之前,必须显式加载驱动类。

import java.sql.*;
public class OracleJDBCOld {
    public static void main(String[] args) {
        // 数据库连接信息
        String dbURL = "jdbc:oracle:thin:@localhost:1521:XE"; // XE是服务名
        String dbUser = "java_user";
        String dbPassword = "your_password";
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            // 1. 加载 JDBC 驱动 (旧版方式)
            Class.forName("oracle.jdbc.driver.OracleDriver");
            // 2. 获取数据库连接
            conn = DriverManager.getConnection(dbURL, dbUser, dbPassword);
            // 3. 创建 Statement 对象
            stmt = conn.createStatement();
            // 4. 执行查询
            String sql = "SELECT id, name, email FROM employees";
            rs = stmt.executeQuery(sql);
            // 5. 处理结果集
            System.out.println("ID\tName\tEmail");
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                System.out.println(id + "\t" + name + "\t" + email);
            }
        } catch (ClassNotFoundException e) {
            System.err.println("找不到 Oracle JDBC 驱动类。");
            e.printStackTrace();
        } catch (SQLException e) {
            System.err.println("数据库连接或查询出错。");
            e.printStackTrace();
        } finally {
            // 6. 关闭资源 (非常重要!)
            try {
                if (rs != null) rs.close();
                if (stmt != null) stmt.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

b. 现代方式 (自动加载)

从 JDBC 4.0 (Java 6+) 开始,DriverManager 会自动在类路径中查找所有实现了 java.sql.Driver 接口的类。Class.forName() 变成了可选的。但显式调用仍然是一个好习惯,因为它明确了你的意图。

Java如何连接Oracle数据库?-图3
(图片来源网络,侵删)

c. 完整的 try-with-resources 示例 (强烈推荐)

try-with-resources 是 Java 7 引入的一个特性,它可以自动实现 AutoCloseable 接口的对象(如 Connection, Statement, ResultSet)的关闭,使代码更简洁、安全。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class OracleJDBCModern {
    // 数据库连接信息,建议放在配置文件中
    private static final String DB_URL = "jdbc:oracle:thin:@localhost:1521:XE";
    private static final String DB_USER = "java_user";
    private static final String DB_PASSWORD = "your_password";
    public static void main(String[] args) {
        // try-with-resources 会自动关闭 Connection, Statement, 和 ResultSet
        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT id, name, email FROM employees")) {
            System.out.println("ID\tName\tEmail");
            while (rs.next()) {
                // 使用列名获取数据,更安全,不易受列顺序影响
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                System.out.println(id + "\t" + name + "\t" + email);
            }
        } catch (SQLException e) {
            System.err.println("数据库操作失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

使用 ojdbc11.jar (Java 11+)

使用 ojdbc11.jarojdbc8.jar 在代码层面几乎没有区别,主要区别在于驱动类名和 Java 版本兼容性。

  • 驱动类名: oracle.jdbc.OracleDriver (与 ojdbc8 相同)
  • JDBC 版本: 支持 JDBC 4.3,try-with-resources 是标准用法。

代码示例与上面的 OracleJDBCModern 完全一致,只需确保你的项目使用的是 Java 11+ 并且依赖的是 ojdbc11.jar


最佳实践

a. 使用连接池 (Connection Pooling)

为什么需要连接池? 每次应用程序需要与数据库交互时,都创建一个新的连接是一个昂贵的操作(涉及网络握手、身份验证等),连接池通过在应用程序启动时创建一组数据库连接并复用它们,极大地提高了性能和可伸缩性。

使用 HikariCP (推荐) HikariCP 是目前公认性能最高、最可靠的 JDBC 连接池实现。

步骤:

  1. 添加 HikariCP 依赖 (Maven):

    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>5.0.1</version> <!-- 使用最新版本 -->
    </dependency>
  2. 配置并使用 HikariCP:

    import com.zaxxer.hikari.HikariConfig;
    import com.zaxxer.hikari.HikariDataSource;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    public class OracleJDBCPooled {
        private static HikariDataSource dataSource;
        static {
            HikariConfig config = new HikariConfig();
            config.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:XE");
            config.setUsername("java_user");
            config.setPassword("your_password");
            // 连接池配置 (可选,推荐设置)
            config.setDriverClassName("oracle.jdbc.driver.OracleDriver");
            config.setMaximumPoolSize(10); // 最大连接数
            config.setMinimumIdle(5);     // 最小空闲连接数
            config.setConnectionTimeout(30000); // 连接超时时间 (ms)
            config.setIdleTimeout(600000); // 空闲连接超时时间 (ms)
            config.setMaxLifetime(1800000); // 连接最大存活时间 (ms)
            dataSource = new HikariDataSource(config);
        }
        public static void main(String[] args) {
            // 从连接池获取连接
            try (Connection conn = dataSource.getConnection();
                 Statement stmt = conn.createStatement();
                 ResultSet rs = stmt.executeQuery("SELECT name FROM employees WHERE id = 1")) {
                if (rs.next()) {
                    String name = rs.getString("name");
                    System.out.println("Employee name: " + name);
                }
            } catch (SQLException e) {
                System.err.println("数据库操作失败: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }

b. 使用 try-with-resources

如上所示,始终使用 try-with-resources 来管理 JDBC 资源,可以防止资源泄漏。

c. 使用 PreparedStatement 防止 SQL 注入

对于任何包含用户输入的 SQL 查询,都应使用 PreparedStatement

// 错误方式 (易受SQL注入攻击)
String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
// 正确方式 (使用PreparedStatement)
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
try (Connection conn = dataSource.getConnection();
     PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setString(1, username); // 设置第一个 '?' 的值
    pstmt.setString(2, password); // 设置第二个 '?' 的值
    try (ResultSet rs = pstmt.executeQuery()) {
        // 处理结果...
    }
}

d. 处理异常

总是捕获 SQLException,并根据情况记录日志或向用户显示友好的错误信息。


常见问题与解决方案

a. ClassNotFoundExceptionNoClassDefFoundError

  • 原因: JVM 在运行时找不到 oracle.jdbc.driver.OracleDriver 类。
  • 解决方案: 确保 ojdbcX.jar 文件已经正确地添加到了项目的类路径中,检查 IDE 的项目结构或构建工具(Maven/Gradle)的配置。

b. Invalid URL format

  • 原因: JDBC URL 格式不正确。
  • 解决方案:
    • 检查协议: jdbc:oracle:thin:
    • 检查主机、端口、服务名/SID: @host:port:service_name@host:port:sid,确保端口号和数据库标识符正确。
    • 区分 SID 和 Service Name:
      • SID: jdbc:oracle:thin:@localhost:1521:ORCL (旧方式)
      • Service Name: jdbc:oracle:thin:@localhost:1521:ORCL.example.com (现代方式,推荐)
    • 使用 SQL*Plus 或 SQL Developer 的 "Test" 功能可以验证连接字符串是否正确。

c. IO Error: The Network Adapter could not establish connection

  • 原因: 无法通过网络连接到数据库监听器。
  • 解决方案:
    1. 检查数据库服务: 确认 Oracle 数据库实例(如 ORCLXE)正在运行。
    2. 检查监听器: 登录到数据库服务器,运行 lsnrctl status 命令,确认监听器正在监听正确的端口(通常是 1521)。
    3. 检查防火墙: 确保运行 Java 应用程序的机器可以访问数据库服务器的 1521 端口。
    4. 检查主机名: 如果数据库和应用程序不在同一台机器上,确保 localhost 被替换为数据库服务器的实际 IP 地址或主机名。

d. ORA-01017: invalid username/password; logon denied

  • 原因: 提供的用户名或密码错误。
  • 解决方案: 仔细核对 DB_USERDB_PASSWORD 变量中的值,确保没有拼写错误,检查用户是否被锁定或密码已过期。
分享:
扫描分享到社交APP
上一篇
下一篇