首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 連接 Oracle 數據庫完整實戰:從環境搭建到 CRUD 操作全流程

     編輯:Java 綜合教學

Java 連接 Oracle 數據庫完整實戰

Oracle 作為企業級數據庫的佼佼者,與 Java 的整合是後端開發的必修課。本文提供從驅動配置、表結構設計、連接參數優化到完整 CRUD 操作的端到端實戰指南,代碼即拿即用,適合快速落地項目。

環境準備與配置

1. 依賴引入 (Maven/Gradle)

<!-- Maven -->
<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>  <!-- JDK 8+ 使用 ojdbc8,JDK 11+ 推薦 ojdbc11 -->
    <version>21.9.0.0</version>
</dependency>


mvn install:install-file -Dfile=ojdbc8.jar -DgroupId=com.oracle -DartifactId=ojdbc8 -Dversion=21.9.0.0 -Dpackaging=jar

注意:Oracle JDBC 驅動因版權原因不在 Maven Central,需從 Oracle 官網下載或配置私服。

2. 數據庫表結構準備

-- 創建學生表
CREATE TABLE student (
    id          NUMBER(11) NOT NULL PRIMARY KEY,
    stu_name    VARCHAR2(16) NOT NULL,
    gender      NUMBER(11) DEFAULT NULL,  -- 1:男 2:女
    age         NUMBER(11) DEFAULT NULL,
    address     VARCHAR2(128) DEFAULT NULL
);

-- 插入測試數據
INSERT INTO student VALUES (1, '王小軍', 1, 17, '北京市和平裡七區30號樓7門102');
COMMIT;

核心連接參數配置

public class OracleConfig {
    // 精簡版 Oracle (XE) 默認配置
    public static final String DRIVER = "oracle.jdbc.OracleDriver";
    public static final String URL = "jdbc:oracle:thin:@192.168.0.100:1521:XE"; // 替換為實際 IP/SID
    public static final String USERNAME = "orcl";
    public static final String PASSWORD = "orcl";
    
    // 生產環境建議使用服務名
    // jdbc:oracle:thin:@//host:port/service_name
    
    // 連接池優化參數 (HikariCP 示例)
    // maximumPoolSize=20
    // minimumIdle=5
    // connectionTimeout=30000
    // idleTimeout=600000
    // maxLifetime=1800000
}

完整 DAO 實現類

public class StudentDao {
    private Connection connection;
    private PreparedStatement pstm;
    private ResultSet rs;
    
    // 獲取連接 (建議配合連接池使用)
    private Connection getConnection() throws SQLException {
        try {
            Class.forName(OracleConfig.DRIVER);
            connection = DriverManager.getConnection(
                OracleConfig.URL, OracleConfig.USERNAME, OracleConfig.PASSWORD);
            System.out.println("✅ Oracle 數據庫連接成功");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("❌ 驅動類未找到", e);
        } catch (SQLException e) {
            throw new RuntimeException("❌ 連接失敗", e);
        }
        return connection;
    }
    
    // 釋放資源 (反向關閉)
    private void releaseResource() {
        try { if (rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); }
        try { if (pstm != null) pstm.close(); } catch (SQLException e) { e.printStackTrace(); }
        try { if (connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); }
    }
    
    // ============ CRUD 操作 ============
    
    // 新增學生 (自動生成 ID)
    public void addStudent(String name, int gender, int age, String address) {
        String countSql = "SELECT COUNT(*) FROM student";
        String insertSql = "INSERT INTO student (id, stu_name, gender, age, address) VALUES (?, ?, ?, ?, ?)";
        
        try {
            getConnection();
            // 獲取當前最大 ID + 1 (生產環境建議使用 Sequence)
            pstm = connection.prepareStatement(countSql);
            rs = pstm.executeQuery();
            int nextId = 1;
            if (rs.next()) nextId = rs.getInt(1) + 1;
            
            // 執行插入
            pstm = connection.prepareStatement(insertSql);
            pstm.setInt(1, nextId);
            pstm.setString(2, name);
            pstm.setInt(3, gender);
            pstm.setInt(4, age);
            pstm.setString(5, address);
            int rows = pstm.executeUpdate();
            System.out.println(rows > 0 ? "✅ 新增成功,ID: " + nextId : "❌ 新增失敗");
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            releaseResource();
        }
    }
    
    // 按姓名刪除
    public void deleteStudentByName(String name) {
        String sql = "DELETE FROM student WHERE stu_name = ?";
        try {
            getConnection();
            pstm = connection.prepareStatement(sql);
            pstm.setString(1, name);
            int rows = pstm.executeUpdate();
            System.out.println(rows > 0 ? "✅ 刪除成功,影響行數: " + rows : "⚠️ 未找到匹配記錄");
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            releaseResource();
        }
    }
    
    // 更新學生信息
    public void updateStudent(String name, int gender, int age, String address) {
        String idSql = "SELECT id FROM student WHERE stu_name = ?";
        String updateSql = "UPDATE student SET stu_name=?, gender=?, age=?, address=? WHERE id=?";
        
        try {
            getConnection();
            // 先查 ID
            pstm = connection.prepareStatement(idSql);
            pstm.setString(1, name);
            rs = pstm.executeQuery();
            int id = 0;
            if (rs.next()) id = rs.getInt(1);
            else { System.out.println("⚠️ 學生不存在"); return; }
            
            // 執行更新
            pstm = connection.prepareStatement(updateSql);
            pstm.setString(1, name);
            pstm.setInt(2, gender);
            pstm.setInt(3, age);
            pstm.setString(4, address);
            pstm.setInt(5, id);
            int rows = pstm.executeUpdate();
            System.out.println(rows > 0 ? "✅ 更新成功" : "❌ 更新失敗");
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            releaseResource();
        }
    }
    
    // 查詢所有學生
    public void queryAllStudents() {
        String sql = "SELECT * FROM student";
        try {
            getConnection();
            pstm = connection.prepareStatement(sql);
            rs = pstm.executeQuery();
            
            System.out.println("ID\t姓名\t性別\t年齡\t地址");
            System.out.println("------------------------------------------------");
            while (rs.next()) {
                System.out.printf("%d\t%s\t%d\t%d\t%s%n",
                    rs.getInt("id"),
                    rs.getString("stu_name"),
                    rs.getInt("gender"),
                    rs.getInt("age"),
                    rs.getString("address"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            releaseResource();
        }
    }
    
    // 使用 ResultSetMetaData 獲取列信息
    public void queryWithMetaData() {
        String sql = "SELECT * FROM student";
        try {
            getConnection();
            pstm = connection.prepareStatement(sql);
            rs = pstm.executeQuery();
            
            ResultSetMetaData meta = rs.getMetaData();
            int columnCount = meta.getColumnCount();
            
            // 打印列名
            for (int i = 1; i <= columnCount; i++) {
                System.out.printf("%-15s", meta.getColumnLabel(i));
            }
            System.out.println();
            
            // 打印數據
            while (rs.next()) {
                for (int i = 1; i <= columnCount; i++) {
                    System.out.printf("%-15s", rs.getObject(i));
                }
                System.out.println();
            }
            System.out.println("列數: " + columnCount);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            releaseResource();
        }
    }
}

測試類與運行結果

public class OracleTest {
    public static void main(String[] args) {
        StudentDao dao = new StudentDao();
        
        System.out.println("=== 1. 查詢初始數據 ===");
        dao.queryAllStudents();
        
        System.out.println("\n=== 2. 新增學生 ===");
        dao.addStudent("孫中山", 1, 25, "北京市海澱區紅旗路111號");
        
        System.out.println("\n=== 3. 查詢新增後 ===");
        dao.queryAllStudents();
        
        System.out.println("\n=== 4. 更新學生 ===");
        dao.updateStudent("孫中山", 1, 30, "北京市東城區岳山路11號");
        
        System.out.println("\n=== 5. 查詢更新後 ===");
        dao.queryAllStudents();
        
        System.out.println("\n=== 6. 刪除學生 ===");
        dao.deleteStudentByName("孫中山");
        
        System.out.println("\n=== 7. 最終數據 ===");
        dao.queryAllStudents();
        
        System.out.println("\n=== 8. 元數據查詢 ===");
        dao.queryWithMetaData();
    }
}

生產環境優化清單

🔧 連接池配置

  • 使用 HikariCP (Spring Boot 默認)
  • 配置 maximumPoolSize 根據 CPU 核心數
  • 啟用 connectionTimeout、idleTimeout、maxLifetime
  • 設置 connectionTestQuery: SELECT 1 FROM DUAL

⚡ SQL 優化

  • 使用 PreparedStatement 防注入 + 預編譯緩存
  • 避免 SELECT *,顯式列出需要的列
  • 大量數據操作使用批處理 addBatch/executeBatch
  • 關鍵查詢添加索引 (WHERE/JOIN 條件列)

🛡️ 異常處理增強

  • 自定義異常體系 (DataAccessException 等)
  • 重試機制 (瞬時錯誤如網絡抖動)
  • 死鎖檢測與處理
  • 慢 SQL 監控 (閾值告警)

📊 事務管理

  • @Transactional 聲明式事務
  • 隔離級別: READ_COMMITTED (Oracle 默認)
  • 傳播行為: REQUIRED (默認)
  • 超時設置: timeout=30 秒

常見問題速查表

錯誤現象可能原因解決方案
ORA-12505: TNS:listener does not currently know of SIDSID/服務名錯誤確認 tnsnames.ora、使用服務名而非 SID
ORA-28040: No matching authentication protocolJDK/驅動版本與數據庫不兼容升級 ojdbc8/11,或數據庫設置 SQLNET.ALLOWED_LOGON_VERSION_SERVER=8
中文亂碼 (???)字符集不匹配確認 NLS_LANG 環境變量、數據庫字符集 AL32UTF8、JVM -Dfile.encoding=UTF-8
連接泄漏導致 ORA-00020未正確關閉連接/連接池配置不當使用 try-with-resources、監控連接池指標、設置 maxLifetime

掌握 Java 操作 Oracle 的核心套路:驅動加載 → 連接獲取 → PreparedStatement 預編譯 → 參數綁定 → 執行 → 結果集處理 → 資源釋放。將此模板內化為肌肉記憶,配合連接池與事務管理,即可應對絕大多數企業級開發場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved