在資料庫中儲存圖片等二進位檔案,Oracle 推薦使用 BLOB (Binary Large Object) 資料型別,配合 DBMS_LOB 套件與 BFILE (外部檔案參照) 實現高效、安全的檔案載入。本文提供從建表、建立目錄物件、撰寫載入 Procedure、到 Java 端讀取顯示的完整端到端範例。
CREATE TABLE image_lob (
t_id VARCHAR2(5) NOT NULL,
t_image BLOB NOT NULL
);
-- 需 CREATE ANY DIRECTORY 權限 (通常由 DBA 執行)
CREATE OR REPLACE DIRECTORY images AS 'C:\Oracle\Images';
-- Linux 範例:CREATE OR REPLACE DIRECTORY images AS '/u01/app/oracle/images';
注意:目錄路徑必須為資料庫伺服器端可存取的實體路徑,非 Client 端路徑。
CREATE OR REPLACE PROCEDURE img_insert (
p_tid IN VARCHAR2,
p_filename IN VARCHAR2
) AS
v_bfile BFILE;
v_blob BLOB;
BEGIN
-- 1. 插入空 BLOB 並取得 LOB Locator
INSERT INTO image_lob (t_id, t_image)
VALUES (p_tid, EMPTY_BLOB())
RETURNING t_image INTO v_blob;
-- 2. 建立 BFILE 指向外部檔案
v_bfile := BFILENAME('IMAGES', p_filename); -- 目錄物件名 + 檔名
-- 3. 唯讀開啟外部檔案
DBMS_LOB.FILEOPEN(v_bfile, DBMS_LOB.FILE_READONLY);
-- 4. 將檔案內容載入 BLOB (一次性載入全長)
DBMS_LOB.LOADFROMFILE(
dest_lob => v_blob,
src_lob => v_bfile,
amount => DBMS_LOB.GETLENGTH(v_bfile)
);
-- 5. 關閉外部檔案
DBMS_LOB.FILECLOSE(v_bfile);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
IF DBMS_LOB.FILEISOPEN(v_bfile) = 1 THEN
DBMS_LOB.FILECLOSE(v_bfile);
END IF;
ROLLBACK;
RAISE;
END img_insert;
/
-- 將 C:\Oracle\Images\f_TEST.jpg 載入 ID='1'
EXEC img_insert('1', 'f_TEST.jpg');
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String imgId = req.getParameter("id"); // 如 ?id=1
if (imgId == null) { resp.sendError(400); return; }
String sql = "SELECT t_image FROM image_lob WHERE t_id = ?";
try (Connection conn = DataSourceUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, imgId);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
Blob blob = rs.getBlob("T_IMAGE");
if (blob != null) {
resp.setContentType("image/jpeg"); // 依實際格式調整
resp.setContentLengthLong(blob.length());
try (InputStream is = blob.getBinaryStream();
OutputStream os = resp.getOutputStream()) {
byte[] buffer = new byte[8192];
int len;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
}
return;
}
}
}
} catch (SQLException e) {
throw new ServletException("DB error", e);
}
resp.sendError(404);
}
}
| 元件 | 角色 | 關鍵方法 |
|---|---|---|
| BLOB | 資料庫內部儲存二進位資料 | EMPTY_BLOB(), RETURNING INTO |
| BFILE | 指向伺服器外部檔案的只讀指標 | BFILENAME(dir, file), FILEOPEN/FILECLOSE |
| DBMS_LOB | LOB 操作核心套件 | LOADFROMFILE, GETLENGTH, READ/WRITE |
| DIRECTORY | 邏輯目錄物件,隔離 OS 路徑 | CREATE DIRECTORY, GRANT READ ON DIRECTORY |
DBMS_LOB.READ/WRITE 分塊處理,避免 PGA 記憶體暴增。CREATE TABLE ... (t_image BLOB STORE AS SECUREFILE) 享有壓縮、重複刪除、加密、緩存優化。GRANT READ ON DIRECTORY images TO app_user;,不給 WRITE。mime_type VARCHAR2(50) 欄位,或由副檔名推斷。掌握 BFILE → DBMS_LOB.LOADFROMFILE → BLOB 這條標準鏈路,即可在 Oracle 中安全、高效地管理圖片等非結構化資料。