JDBC 處理 Blob(二進制大對象)與 Clob(字符大對象)並不複雜,關鍵在於「流的轉換與傳輸」。本文以嵌入式數據庫 Apache Derby 為例,演示建表、寫入、讀取全流程,兩種流獲取方式對比,適用於 MySQL、Oracle、PostgreSQL 等主流數據庫。
derby.jar 加入 Classpath。org.apache.derby.jdbc.EmbeddedDriver。jdbc:derby:dbName;create=true(自動建庫)。CREATE TABLE documents (
id INT,
text CLOB(64K), -- 64KB 字符大對象
photo BLOB(1440K) -- 1.4MB 二進制大對象
)
File srcCode = new File("BlobClobExample.java");
File image = new File("c:/11/1.JPG");
PreparedStatement ps = conn.prepareStatement("INSERT INTO documents VALUES (?, ?, ?)");
ps.setInt(1, 250);
ps.setAsciiStream(2, new FileInputStream(srcCode), (int) srcCode.length()); // Clob
ps.setBinaryStream(3, new FileInputStream(image), (int) image.length()); // Blob
ps.execute();
conn.commit();
要點: 必須使用 PreparedStatement,傳入 InputStream 與精確長度,JDBC 驅動分塊傳輸避免 OOM。
ResultSet rs = stmt.executeQuery("SELECT text, photo FROM documents WHERE id=250");
while (rs.next()) {
// Clob 字符流
InputStream is = rs.getAsciiStream("text");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = br.readLine()) != null) System.out.println(line);
is.close();
// Blob 二進制流
InputStream bis = rs.getBinaryStream("photo");
FileOutputStream os = new FileOutputStream("11.jpg");
int b;
while ((b = bis.read()) != -1) os.write(b);
os.flush(); os.close(); bis.close();
}
Clob clob = rs.getClob("text");
InputStream is = clob.getAsciiStream(); // 等價於方式一
Blob blob = rs.getBlob("photo");
InputStream bis = blob.getBinaryStream(); // 等價於方式一
long len = blob.length(); // 額外獲得長度信息
方式二適合需要操作 Blob.length()、Clob.getSubString() 等高級 API 時。
| 數據庫 | 驅動類 | 大對象類型名 | 備註 |
|---|---|---|---|
| MySQL | com.mysql.cj.jdbc.Driver | BLOB/TEXT/LONGBLOB/LONGTEXT | 需 useStreamLengthsInPrepStmts=true |
| Oracle | oracle.jdbc.OracleDriver | BLOB/CLOB | 需 oracle.sql.BLOB 特定 API 處理大對象 |
| PostgreSQL | org.postgresql.Driver | BYTEA/TEXT | 大對象需 LargeObjectManager API |
| SQL Server | com.microsoft.sqlserver.jdbc.SQLServerDriver | VARBINARY(MAX)/VARCHAR(MAX) | 標準 JDBC 4.0 完美支持 |
核心代碼(setBinaryStream/getBinaryStream)在 JDBC 4.0+ 驅動中通用,僅建表 DDL 與特定擴展 API 有差異。