杰瑞科技汇

Java如何连接Oracle数据库?

  1. 核心概念:JDBC 和 JDBC 驱动程序
  2. 环境准备:下载并配置 Oracle 驱动
  3. 核心代码示例:从建立连接到执行查询
  4. 最佳实践:使用 try-with-resourcesPreparedStatement
  5. 连接池 (Connection Pooling):提升性能的关键
  6. 常见问题与解决方案

核心概念:JDBC 和 JDBC 驱动程序

  • JDBC (Java Database Connectivity):这是 Java 提供的一套标准 API,用于执行 SQL 语句,它定义了如何从 Java 程序连接到各种数据库、执行查询、获取结果等操作,你可以把它想象成 Java 和数据库之间的“通用翻译官”。
  • JDBC 驱动程序 (Driver):数据库厂商(如 Oracle)提供的实现类,它负责将 JDBC 的标准调用“翻译”成该特定数据库能理解的协议,没有驱动,JDBC API 就无法与 Oracle 数据库通信。

对于 Oracle 数据库,我们通常使用 Oracle JDBC Thin Driver,这是一个纯 Java 的驱动,无需在客户端安装 Oracle 客户端软件,非常适合大多数应用场景。

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

环境准备:下载并配置 Oracle 驱动

在编写代码之前,你需要获取 Oracle JDBC 驱动的 JAR 包。

步骤 1: 下载驱动

最推荐的下载方式是使用 Maven 或 Gradle,这样可以自动管理依赖。

使用 Maven (推荐)

在你的 pom.xml 文件中添加以下依赖:

Java如何连接Oracle数据库?-图2
(图片来源网络,侵删)
<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>19.3.0.0</version> <!-- 请根据你的 Oracle 数据库版本选择合适的版本 -->
</dependency>
  • 注意ojdbc8 用于 Java 8 和更高版本,如果你的项目使用 Java 6 或 7,需要使用 ojdbc7

手动下载 JAR 包

如果你不使用 Maven,可以从 Oracle 官网或 Maven 中央仓库下载 JAR 包。

下载后,将 JAR 文件添加到你的项目的类路径中。

步骤 2: 准备 Oracle 数据库

确保你有一个可用的 Oracle 数据库实例,并且你知道以下连接信息:

  • URL: 格式通常为 jdbc:oracle:thin:@<host>:<port>:<service_name>
    • host: 数据库服务器的 IP 地址或主机名 (如 localhost168.1.100)
    • port: 数据库监听的端口 (默认为 1521)
    • service_name: 数据库的服务名 (SID 在较新版本中已不推荐使用),你可以通过 SQL*Plus 或 SQL Developer 查询。
  • 用户名: 你的数据库用户名 (如 scott)
  • 密码: 你的数据库密码 (如 tiger)

核心代码示例

下面是一个完整的、可运行的 Java 示例,演示了如何连接到 Oracle 数据库、执行查询并处理结果。

示例代码

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class OracleJdbcExample {
    // 数据库连接信息 - 请根据你的环境修改
    private static final String DB_URL = "jdbc:oracle:thin:@localhost:1521:ORCLCDB"; // 请替换为你的URL
    private static final String USER = "your_username";       // 请替换为你的用户名
    private static final String PASS = "your_password";       // 请替换为你的密码
    public static void main(String[] args) {
        // try-with-resources 语句,确保资源在使用后被自动关闭
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT * FROM EMP")) { // 假设你有一个EMP表
            // 检查连接是否成功
            if (conn != null) {
                System.out.println("成功连接到 Oracle 数据库!");
            }
            // 遍历结果集
            System.out.println("EMPNO ENAME  JOB         MGR HIREDATE         SAL     COMM     DEPTNO");
            System.out.println("------------------------------------------------------------------------");
            while (rs.next()) {
                // 通过列名获取数据,更具可读性且不易出错
                int empno = rs.getInt("EMPNO");
                String ename = rs.getString("ENAME");
                String job = rs.getString("JOB");
                int mgr = rs.getInt("MGR");
                java.sql.Date hiredate = rs.getDate("HIREDATE");
                double sal = rs.getDouble("SAL");
                double comm = rs.getDouble("COMM");
                int deptno = rs.getInt("DEPTNO");
                System.out.printf("%-5d %-7s %-11s %-5d %-12s %-8.2f %-8.2f %d%n",
                        empno, ename, job, mgr, hiredate, sal, comm, deptno);
            }
        } catch (SQLException e) {
            System.err.println("数据库操作失败!");
            e.printStackTrace();
        }
    }
}

代码解析

  1. 加载驱动:在现代 JDBC (4.0+) 中,通常不需要显式调用 Class.forName("oracle.jdbc.OracleDriver"),当你调用 DriverManager.getConnection() 时,驱动管理器会自动在类路径中查找并加载合适的驱动。
  2. 建立连接DriverManager.getConnection(DB_URL, USER, PASS) 是核心方法,它使用提供的 URL、用户名和密码建立与数据库的连接。
  3. 创建 Statementconn.createStatement() 创建一个 Statement 对象,用于执行 SQL 语句。
  4. 执行查询stmt.executeQuery("SELECT ...") 执行一个查询语句,并返回一个 ResultSet 对象,该对象包含了查询结果。
  5. 处理结果集
    • rs.next(): 将光标移动到下一行,如果存在下一行则返回 true
    • rs.getXXX("列名"): 根据列名获取当前行的数据,XXX 是数据类型(如 getInt, getString, getDate 等),推荐使用列名而不是列索引。
  6. 关闭资源try-with-resources 语句是 Java 7+ 的特性,它能确保 Connection, Statement, 和 ResultSet 这些实现了 AutoCloseable 接口的资源在代码块执行完毕后自动被关闭,即使发生异常也是如此,这是防止资源泄漏的最佳实践。

最佳实践:使用 PreparedStatement

在上述示例中,我们使用了 Statement,但在实际开发中,强烈推荐使用 PreparedStatement,尤其是在执行带参数的 SQL 查询时。

为什么使用 PreparedStatement

  1. 防止 SQL 注入PreparedStatement 会对输入参数进行转义处理,从根本上杜绝了 SQL 注入的风险。
  2. 性能更优:数据库可以预编译 PreparedStatement 的 SQL 语句,如果同一个 SQL 被多次执行(只是参数不同),数据库可以重用预编译的执行计划,提高效率。
  3. 代码更清晰:使用 作为占位符,代码更易读和维护。

使用 PreparedStatement 的示例

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class OraclePreparedStatementExample {
    private static final String DB_URL = "jdbc:oracle:thin:@localhost:1521:ORCLCDB";
    private static final String USER = "your_username";
    private static final String PASS = "your_password";
    public static void findEmployeeByName(String namePattern) {
        // SQL 查询语句,使用 ? 作为参数占位符
        String sql = "SELECT EMPNO, ENAME, JOB FROM EMP WHERE ENAME LIKE ?";
        // try-with-resources 确保 conn, stmt, rs 都被关闭
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 设置参数,索引从 1 开始
            pstmt.setString(1, "%" + namePattern + "%");
            // 执行查询
            try (ResultSet rs = pstmt.executeQuery()) {
                System.out.println("查找名字包含 '" + namePattern + "' 的员工:");
                System.out.println("EMPNO ENAME  JOB");
                System.out.println("--------------------");
                while (rs.next()) {
                    System.out.printf("%-5d %-7s %s%n",
                            rs.getInt("EMPNO"), rs.getString("ENAME"), rs.getString("JOB"));
                }
            }
        } catch (SQLException e) {
            System.err.println("查询失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        findEmployeeByName("SM");
    }
}

连接池 (Connection Pooling)

每次需要数据库操作时都创建一个新的连接,是一个开销很大的过程,连接池技术就是为了解决这个问题而生的。

什么是连接池? 连接池是一个预先创建并维护一定数量的数据库连接对象的“池子”,当应用程序需要一个连接时,它从池中获取一个已存在的连接,用完后将其归还到池中,而不是关闭它,这样可以极大地减少连接创建和销毁的开销,显著提升应用性能。

常用的 Java 连接池库:

  • HikariCP: 目前性能最好、最受欢迎的连接池,Spring Boot 2.x 默认使用它。
  • Apache DBCP (Database Connection Pool): 一个经典的开源连接池实现。
  • C3P0: 另一个老牌的连接池实现。

使用 HikariCP 的示例

添加 HikariCP 的 Maven 依赖:

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>5.0.1</version> <!-- 使用最新稳定版 -->
</dependency>

修改代码以使用连接池:

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;
public class OracleWithHikariCPExample {
    // 使用 HikariDataSource 作为连接池
    private static HikariDataSource dataSource;
    // 静态代码块,在类加载时初始化连接池
    static {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:ORCLCDB");
        config.setUsername("your_username");
        config.setPassword("your_password");
        config.setDriverClassName("oracle.jdbc.OracleDriver");
        // 连接池配置 (可根据实际情况调整)
        config.setMaximumPoolSize(10); // 最大连接数
        config.setMinimumIdle(5);      // 最小空闲连接数
        config.setConnectionTimeout(30000); // 连接超时时间 (毫秒)
        config.setIdleTimeout(600000); // 空闲连接超时时间
        config.setMaxLifetime(1800000); // 连接最大存活时间
        dataSource = new HikariDataSource(config);
    }
    public static void main(String[] args) {
        // 从连接池中获取一个连接
        try (Connection conn = dataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement("SELECT ENAME FROM EMP WHERE DEPTNO = ?")) {
            pstmt.setInt(1, 10); // 查询 10 号部门的员工
            try (ResultSet rs = pstmt.executeQuery()) {
                System.out.println("10 号部门的员工:");
                while (rs.next()) {
                    System.out.println(rs.getString("ENAME"));
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // 注意:在应用程序关闭时,应该关闭连接池
        // dataSource.close();
    }
}

常见问题与解决方案

问题 1: java.sql.SQLException: No suitable driver found

  • 原因:JDBC 驱动 JAR 文件没有添加到项目的类路径中。
  • 解决方案:确保 ojdbc8.jar (或你下载的版本) 在你的构建路径中,如果你使用 IDE (如 IntelliJ IDEA, Eclipse),请检查库是否已正确添加,如果你使用 Maven/Gradle,确保依赖已下载并生效。

问题 2: java.sql.SQLException: Listener refused the connection with the following error: ORA-12505, TNS:no listener

  • 原因:数据库 URL 中的端口号 (1521) 或服务名 (ORCLCDB) 错误,数据库服务器可能没有运行,或者监听器没有配置为监听该服务名。
  • 解决方案
    1. 使用 tnsping 命令测试监听是否正常:tnsping ORCLCDB
    2. 使用 SQL*Plus 或 SQL Developer 尝试手动连接,验证用户名、密码、主机、端口和服务名是否全部正确。

问题 3: java.sql.SQLException: Invalid username/password; logon denied

  • 原因:提供的数据库用户名或密码错误。
  • 解决方案:仔细检查用户名和密码,注意大小写。

问题 4: java.sql.SQLException: The Network Adapter could not establish the connection

  • 原因:网络问题,Java 应用程序无法到达数据库服务器。
  • 解决方案
    1. 检查数据库服务器的 IP 地址是否正确。
    2. 检查防火墙是否阻止了 1521 端口的通信。
    3. 确保数据库服务器正在运行。
技术点 关键点
驱动 使用 ojdbc8.jar (Java 8+),通过 Maven/Gradle 管理依赖。
连接 使用 DriverManager.getConnection(),URL 格式为 jdbc:oracle:thin@...
核心对象 Connection (连接), Statement/PreparedStatement (执行SQL), ResultSet (结果集)。
最佳实践 必须使用 try-with-resources 关闭资源;强烈推荐使用 PreparedStatement 防止注入并提升性能。
性能优化 必须使用连接池(如 HikariCP)来管理数据库连接,避免频繁创建和销毁连接。
错误处理 捕获 SQLException,并根据错误信息(如 ORA- 错误码)排查问题。

你就可以在 Java 应用中稳定、高效地与 Oracle 数据库进行交互了。

分享:
扫描分享到社交APP
上一篇
下一篇