首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

Java + Oracle 應用開發三大常見問題:JDBC 驅動加載、BLOB 存儲、可滾動結果集

     編輯:Oracle 資料庫相關知識

問題一:JDBC 驅動加載的三種方式與選擇

方式代碼優點缺點/避坑
Class.forNameClass.forName("oracle.jdbc.OracleDriver")簡單、標準 JDBCMS JVM (IE Applet) 無法正確初始化靜態塊
系統屬性文件System.getProperties().load(...) 配置 jdbc.drivers=oracle.jdbc.OracleDriver解耦驅動類名、多驅動並行、無需改代碼換庫需確保屬性文件在 Classpath、加載時機
DriverManager.registerDriverDriverManager.registerDriver(new oracle.jdbc.OracleDriver())最可靠、任何環境 (含 Applet) 均可用硬編碼驅動類、靈活性最低

建議: 現代應用 (Spring Boot 等) 由連接池 (HikariCP/Druid) 自動加載,無需手工編寫。

問題二:大對象 (BLOB) 正確存取姿勢

誤區:JDBC 2.0 標準 API 不支持直接寫入 BLOB

-- 錯誤嘗試
pstmt.setBinaryStream(1, inputStream, length);  -- 針對 LONG RAW,非 BLOB
-- 會拋 IO Exception 而非 SQLException

正解:Oracle 擴展 API (oracle.sql.BLOB)

// 1. 插入空 BLOB 佔位
conn.setAutoCommit(false);
stmt.executeUpdate("INSERT INTO tb_file(name, detail) VALUES ('a.gif', EMPTY_BLOB())");

// 2. 查回 BLOB 定位器 (FOR UPDATE 鎖定)
ResultSet rs = stmt.executeQuery("SELECT detail FROM tb_file WHERE name='a.gif' FOR UPDATE");
rs.next();
BLOB blob = ((OracleResultSet)rs).getBLOB(1);  // 或 rs.getBlob(1) 強轉

// 3. 獲取輸出流寫入
try (OutputStream out = blob.setBinaryStream(1);  // 1-based 位置
     InputStream in = new FileInputStream(file)) {
    byte[] buf = new byte[blob.getBufferSize()];
    int len;
    while ((len = in.read(buf)) != -1) out.write(buf, 0, len);
}
conn.commit();

讀取 BLOB

Blob blob = rs.getBlob("detail");
try (InputStream in = blob.getBinaryStream()) {
    // 處理輸入流
}

關鍵點: 必須 FOR UPDATE 鎖定行、關閉自動提交、使用 Oracle 擴展類 (oracle.sql.BLOB) 獲取流。

問題三:可滾動結果集 的陷阱

  • Oracle **不支持** 服務端游標滾動 (TYPE_SCROLL_INSENSITIVE/SENSITIVE)。
  • JDBC 驅動實現是**全量抓取到客戶端內存**模擬滾動。
  • 大結果集 (10 萬+ 行) 會導致 **OOM / GC 風暴 / 響應超時**。

正確姿勢:

  1. 分頁查詢 (OFFSET/FETCH 或 ROWNUM) 推回數據庫。
  2. 流式處理:setFetchSize(1000) + 循環 rs.next() 逐行消費,不緩存全量。
  3. 若必須隨機訪問,先導入臨時表/內存數據庫 (H2/Redis) 再查詢。

補充:連接池最佳實踐 (HikariCP)

dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
dataSource.setJdbcUrl("jdbc:oracle:thin:@(DESCRIPTION=...)");
dataSource.setUsername("app");
dataSource.setPassword("pwd");
dataSource.setMaximumPoolSize(20);
dataSource.setMinimumIdle(5);
dataSource.setConnectionTimeout(5000);
dataSource.setIdleTimeout(300000);
dataSource.setMaxLifetime(1200000);
dataSource.setConnectionInitSql("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved