Oracle BLOB 欄位效能優於 LONG,適合儲存圖片等二進位資料。寫入方式特殊:必須先插入 EMPTY_BLOB() 取得定位器,再透過輸出流寫入資料。本文提供完整 JDBC 範例,Hibernate 同理。
conn.setAutoCommit(false)INSERT INTO javatest(name, content) VALUES (?, EMPTY_BLOB())SELECT content FROM javatest WHERE name=? FOR UPDATE 取得 oracle.sql.BLOB 物件blob.getBinaryOutputStream() 取得輸出流import java.sql.*;
import java.io.*;
import oracle.sql.*;
public class WriteBlob {
public static void main(String[] args) {
try {
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl", "fankai", "fankai");
conn.setAutoCommit(false);
// 1. 插入空 BLOB
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO javatest(name, content) VALUES (?, EMPTY_BLOB())");
pstmt.setString(1, "fankai");
pstmt.executeUpdate();
pstmt.close();
// 2. 取得 BLOB 定位器
pstmt = conn.prepareStatement(
"SELECT content FROM javatest WHERE name = ? FOR UPDATE");
pstmt.setString(1, "fankai");
ResultSet rset = pstmt.executeQuery();
BLOB blob = null;
if (rset.next()) blob = (BLOB) rset.getBlob(1);
pstmt.close(); rset.close();
// 3. 寫入檔案資料
String fileName = "oraclejdbc.jar";
File f = new File(fileName);
FileInputStream fin = new FileInputStream(f);
System.out.println("file size = " + fin.available());
OutputStream out = blob.getBinaryOutputStream();
byte[] data = new byte[(int) fin.available()];
fin.read(data);
out.write(data);
fin.close(); out.close();
conn.commit();
conn.close();
System.out.println("BLOB 寫入完成");
} catch (Exception e) {
e.printStackTrace();
}
}
}
byte[] data = new byte[blob.getBufferSize()];
int count, total = 0;
while ((count = fin.read(data)) != -1) {
total += count;
out.write(data, 0, count);
}
實體類別欄位型別用 java.sql.Blob 或 byte[](配合 @Lob),Session 操作邏輯相同:先 save() 取得 ID,再 lock() 為 LockMode.UPGRADE 取得 Blob 物件寫入。建議使用 Hibernate 的 LobCreator API 簡化流程。
關鍵提醒:務必使用 FOR UPDATE 鎖定列,否則取得的 BLOB 定位器無效;交易未提交前資料不可見。