首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

Java 操作 Oracle BLOB 欄位錯誤解決:Internal Error Unable to construct Datum

     編輯:Oracle 資料庫相關知識

錯誤現象

java.sql.SQLException: Internal Error: Unable to construct a Datum from the specified input

發生環境:Oracle 8.1.7,JDBC 更新含 BLOB 欄位的資料表,使用 ResultSet.updateBinaryStream() 時拋出。

根本原因

使用了 FileInputStream 作為輸入流來源。FileInputStream 未完整實作 java.io.InputStream 介面的所有方法,Oracle JDBC 驅動程式在建構 Datum 物件時需要呼叫這些方法,導致失敗。

解決方案

改用 java.io.File 物件直接傳遞,或包裝為支援完整介面的流物件。

錯誤代碼

// 錯誤寫法
FileInputStream fis = new FileInputStream("image.jpg");
resultSet.updateBinaryStream("blob_col", fis, file.length());

正確代碼

// 寫法 1:直接使用 File 物件 (Oracle JDBC 擴充支援)
File file = new File("image.jpg");
resultSet.updateBinaryStream("blob_col", file);

// 寫法 2:使用 FileInputStream 但包裝為 BufferedInputStream
FileInputStream fis = new FileInputStream("image.jpg");
BufferedInputStream bis = new BufferedInputStream(fis);
resultSet.updateBinaryStream("blob_col", bis, file.length());

// 寫法 3:使用 PreparedStatement + setBinaryStream (推薦)
PreparedStatement ps = conn.prepareStatement(
  "UPDATE table SET blob_col = ? WHERE id = ?");
File file = new File("image.jpg");
ps.setBinaryStream(1, new FileInputStream(file), file.length());
ps.setInt(2, id);
ps.executeUpdate();

最佳實踐建議

  1. 優先使用 PreparedStatement:效能更好、防 SQL 注入、資源管理更清晰
  2. 使用 try-with-resources (Java 7+) 確保流正確關閉
  3. 大物件分塊處理:超大 BLOB 建議使用 DBMS_LOB 或 oracle.sql.BLOB API 分段寫入
  4. 驅動版本相容:Oracle 8.1.7 較舊,建議升級至 11g/12c/19c/21c 配合對應版本 JDBC 驅動

完整範例:PreparedStatement 寫入 BLOB

public void updateBlob(int id, File file) throws SQLException, IOException {
    String sql = "UPDATE my_table SET blob_data = ? WHERE id = ?";
    
    try (Connection conn = dataSource.getConnection();
         PreparedStatement ps = conn.prepareStatement(sql);
         FileInputStream fis = new FileInputStream(file)) {
        
        ps.setBinaryStream(1, fis, file.length());
        ps.setInt(2, id);
        ps.executeUpdate();
    }
}

補充:讀取 BLOB

// 讀取並寫入檔案
ResultSet rs = stmt.executeQuery("SELECT blob_data FROM my_table WHERE id = 1");
if (rs.next()) {
    Blob blob = rs.getBlob("blob_data");
    try (InputStream is = blob.getBinaryStream();
         FileOutputStream fos = new FileOutputStream("output.jpg")) {
        byte[] buffer = new byte[8192];
        int len;
        while ((len = is.read(buffer)) != -1) {
            fos.write(buffer, 0, len);
        }
    }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved