| 方式 | 代碼 | 優點 | 缺點/適用場景 |
|---|---|---|---|
| 1. Class.forName | Class.forName("oracle.jdbc.OracleDriver") | 最常見、規格標準 | MS JVM (IE Applet) 無法正確執行靜態初始化區塊註冊驅動 |
| 2. 系統屬性檔 | jdbc.drivers=oracle.jdbc.OracleDriver 在屬性檔 | 可同時載入多驅動、切換資料庫無需改代碼 | 需確保屬性檔被 JVM 讀取 (啟動參數 -D 或 System.getProperties().load()) |
| 3. 手動註冊 (最可靠) | DriverManager.registerDriver(new oracle.jdbc.OracleDriver()) | 任何環境 (含 Applet、OSGi、模組化) 均生效 | 靈活度較低、硬編碼類名 |
建議:一般 Web 應用用方式 1;Applet/特殊容器用方式 3;需多資料庫熱切換用方式 2。
誤區:以為 PreparedStatement.setBinaryStream 可直接寫入 BLOB,實則拋出 IOException 而非 SQLException,JDBC 2.0 標準不支援直接流寫入 BLOB。
CREATE TABLE tb_file (name VARCHAR2(20), detail LONG RAW);
File file = new File("image.gif");
try (InputStream fin = new FileInputStream(file);
PreparedStatement ps = conn.prepareStatement("INSERT INTO tb_file VALUES (?, ?)")) {
ps.setString(1, file.getName());
ps.setBinaryStream(2, fin, (int)file.length());
ps.executeUpdate();
}
讀取:ResultSet.getBinaryStream("detail") 直接回傳 InputStream。
CREATE TABLE tb_file (name VARCHAR2(20), detail BLOB);
// 1. 插入空 BLOB 定位器
conn.setAutoCommit(false);
try (Statement stmt = conn.createStatement()) {
stmt.executeUpdate("INSERT INTO tb_file VALUES ('image.gif', EMPTY_BLOB())");
}
// 2. 查回 BLOB 定位器 (FOR UPDATE 鎖定)
Blob blob;
try (ResultSet rs = stmt.executeQuery(
"SELECT detail FROM tb_file WHERE name='image.gif' FOR UPDATE")) {
rs.next();
blob = rs.getBlob(1);
}
// 3. 取得輸出流寫入
try (OutputStream out = ((oracle.sql.BLOB)blob).getBinaryOutputStream();
InputStream fin = new FileInputStream(file)) {
byte[] buf = new byte[blob.getBufferSize()];
int len;
while ((len = fin.read(buf)) != -1) out.write(buf, 0, len);
}
conn.commit();
讀取:Blob blob = rs.getBlob("detail"); InputStream in = blob.getBinaryStream();
// 寫入
try (PreparedStatement ps = conn.prepareStatement("INSERT INTO tb_file VALUES (?, ?)");
InputStream fin = new FileInputStream(file)) {
ps.setString(1, file.getName());
ps.setBlob(2, fin); // JDBC 4.0 標準,驅動內部處理 EMPTY_BLOB + 寫入
ps.executeUpdate();
}
// 讀取
try (ResultSet rs = stmt.executeQuery("SELECT detail FROM tb_file WHERE name=?")) {
rs.next();
try (InputStream in = rs.getBlob(1).getBinaryStream()) {
// 處理流
}
}
總結:Oracle 11g+ 驅動完整支援 JDBC 4.0 setBlob/getBlob,請直接使用標準 API,避免 Oracle 專有類別綁定。
正確做法:
TYPE_FORWARD_ONLY (預設),單向流式處理。OFFSET ... FETCH NEXT ... (12c+) 或 ROWNUM 分頁。Class.forName,特殊環境手動註冊。setBlob/getBlob,棄用 LONG RAW 及 Oracle 專有 oracle.sql.BLOB。maxLifetime, idleTimeout, connectionTestQuery。