本文針對 JDBC 驅動載入、大物件 (LOB) 儲存、可捲動結果集三大經典議題,提供最佳實務與避坑指南。
| 方式 | 程式碼 | 優缺點 |
|---|---|---|
| 1. Class.forName | Class.forName("oracle.jdbc.driver.OracleDriver") | 簡單,但 MS JVM (IE Applet) 無法正確初始化靜態區塊 |
| 2. 系統屬性檔 | System.getProperties().load(new FileInputStream("jdbc.properties"))檔案內: jdbc.driver=oracle.jdbc.driver.OracleDriver | 可同時載入多驅動,切換資料庫無需改代碼,彈性佳 |
| 3. 直接註冊 | DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()) | 最可靠,任何環境皆適用,但彈性較差 |
建議:Applet 環境用方式 3;一般應用綜合考量彈性與可靠性選擇。
網路 99% 教學錯誤,甚至 Sun 官方文件也有小錯誤。JDBC 2.0 無法直接對 BLOB 寫入二進位資料,嘗試會拋出 IO Exception 而非 SQL Exception。
CREATE TABLE tb_file (name VARCHAR2(20), detail LONG RAW);
File file = new File("aaa.gif");
int len = (int) file.length();
InputStream fin = new FileInputStream(file);
PreparedStatement pstmt = con.prepareStatement("INSERT INTO tb_file VALUES ('aaa.gif', ?)");
pstmt.setBinaryStream(1, fin, len);
pstmt.executeUpdate();
CREATE TABLE tb_file (name VARCHAR2(20), detail BLOB);
con.setAutoCommit(false);
Statement stmt = con.createStatement();
stmt.executeUpdate("INSERT INTO tb_file VALUES ('aaa.gif', EMPTY_BLOB())");
// 必須 SELECT FOR UPDATE 取得 BLOB 定位器
ResultSet rs = stmt.executeQuery("SELECT detail FROM tb_file WHERE name='aaa.gif' FOR UPDATE");
if (rs.next()) {
BLOB blob = rs.getBlob(1);
OutputStream out = ((oracle.sql.BLOB)blob).getBinaryOutputStream();
byte[] buf = new byte[blob.getBufferSize()];
InputStream fin = new FileInputStream(file);
int read;
while ((read = fin.read(buf)) != -1) out.write(buf, 0, read);
fin.close(); out.close(); con.commit();
}
讀取 BLOB 同樣需 blob.getBinaryStream(),不可用 rs.getBinaryStream()。
ROWNUM、分析函數或 Oracle 12c+ 的 OFFSET ... FETCH。掌握這三大議題,能避開 Java-Oracle 開發中最常見的效能與穩定性地雷。