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

Java + Oracle 開發三大經典難題:驅動加載、大對象存儲、可滾動結果集

     編輯:Java 相關知識

問題一:JDBC 驅動加載的三種姿勢與選擇

方式 1:Class.forName() —— 最常用

Class.forName("oracle.jdbc.driver.OracleDriver");
// 觸發驅動類靜態塊,自動調用 DriverManager.registerDriver()

簡單直接,但 Microsoft JVM (IE Applet 環境) 無法正確初始化,已棄用場景慎用。

方式 2:系統屬性文件 —— 靈活切換數據庫

// jdbc.properties
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@host:1521:sid
jdbc.user=scott
jdbc.password=tiger

// 代碼
Properties props = new Properties();
props.load(new FileInputStream("jdbc.properties"));
Class.forName(props.getProperty("jdbc.driver"));

優點:換庫不動代碼,支持多驅動並存。缺點:略顯繁瑣。

方式 3:DriverManager.registerDriver() —— 最可靠


DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

直接實例化驅動註冊,任何環境 (含 Applet) 均可用。靈活性稍弱,可結合方式 2 動態實例化。

建議:現代項目優先方式 2 + 配置中心;舊 Applet 維護用方式 3。

問題二:大對象 (LOB) 存儲 —— BLOB vs LONG RAW 坑點全解

誤區:JDBC 2.0 標準 API 直接操作 BLOB?

❌ pstmt.setBinaryStream(1, in, len) 對 BLOB 無效,拋 IO 異常而非 SQL 異常。Sun 文檔長期誤導。

方案 A:用 LONG RAW(簡單但受限)

CREATE TABLE tb_file (name VARCHAR2(20), detail LONG RAW);
PreparedStatement pstmt = con.prepareStatement("INSERT INTO tb_file VALUES (?, ?)");
pstmt.setBinaryStream(1, new FileInputStream(file), fileLength);
pstmt.executeUpdate();
// 讀取同理用 getBinaryStream()

缺點:單表僅 1 個 LONG RAW、無法用於 WHERE/ORDER BY、Oracle 12c+ 已不推薦。

方案 B:標準 BLOB 操作(Oracle 專有 API,麻煩但正規)


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

// 2. 查詢 FOR UPDATE 鎖定行,獲取 BLOB 定位器
ResultSet rs = stmt.executeQuery(
    "SELECT detail FROM tb_file WHERE name='a.gif' FOR UPDATE"
);
if (rs.next()) {
    oracle.sql.BLOB blob = (oracle.sql.BLOB) rs.getBlob(1);
    OutputStream out = blob.getBinaryOutputStream();
    // 分塊寫入
    byte[] buf = new byte[blob.getBufferSize()];
    int len;
    while ((len = in.read(buf)) != -1) out.write(buf, 0, len);
    in.close(); out.close(); con.commit();
}

// 3. 讀取
Blob blob = rs.getBlob("detail");
InputStream in = blob.getBinaryStream(); // 而非 getBinaryStream("detail")

關鍵點:FOR UPDATE、EMPTY_BLOB()、getBinaryOutputStream()、事務控制。
現代最佳實踐:JDBC 4.0+ / Oracle 10g+ 支持標準 setBlob()/getBlob() 流式操作,優先使用標準 API,僅在舊版本回退專有做法。

問題三:可滾動結果集 —— 記憶體陷阱

Oracle 數據庫原生不支持服務端游標滾動。JDBC 驅動實現 TYPE_SCROLL_INSENSITIVE 時,實際是將全量結果集拉入客戶端內存。

後果

  • 小數據量:看似正常
  • 大數據量 (萬行+):客戶端 OOM、GC 風暴、響應超時

正確姿勢

  1. 默認使用 TYPE_FORWARD_ONLY(前向只讀,流式處理)
  2. 分頁查詢:Oracle 12c+ 用 OFFSET ... FETCH,舊版用 ROWNUM 子查詢
  3. 確需隨機訪問:在業務層緩存關鍵數據(如 Redis),而非依賴 JDBC 滾動

原則:寧可笨拙的分頁查詢,不可隱形的內存災難。

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