首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JDBC 進階資料類型完整應用指南:BLOB/CLOB、結構化類型、DISTINCT、陣列/REF、DataLink 實戰詳解

     編輯:Java 相關知識

JDBC 版本與支援矩陣

JDBC 版本新增進階類型核心 API
JDBC 2.0 (JDK 1.2)BLOB, CLOB, ARRAY, REF, STRUCT, DISTINCT, JAVA_OBJECTPreparedStatement.setObject, ResultSet.getObject, getBlob/getClob, getArray/getRef
JDBC 3.0 (JDK 1.4)BOOLEAN, DATALINKsetBoolean/getBoolean, setURL/getURL

核心操作模式:寫入用 PreparedStatement,讀取用 ResultSet。

1. BLOB 與 CLOB:大物件處理

型別定義與適用場景

  • BLOB (Binary Large Object):位元組序列——圖片、音訊、視訊、PDF、序列化物件
  • CLOB (Character Large Object):超長字串——XML 文檔、日誌、長文本、JSON

標準 JDBC API

資料庫間複製 BLOB (零記憶體佔用)

// 1. 讀取來源表 BLOB 引用
String sql = "SELECT blob_col FROM blob_table WHERE id = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 1);
ResultSet rs = ps.executeQuery();
Blob blob = null;
if (rs.next()) blob = rs.getBlob(1);  // 僅獲取定位器,不載入實際資料

// 2. 寫入目標表
sql = "INSERT INTO blob_table_2 VALUES (?)";
ps = conn.prepareStatement(sql);
ps.setBlob(1, blob);  // 直接傳遞定位器
ps.executeUpdate();

檔案 ↔ BLOB 流式讀寫 (JDBC 2.0 + 廠商擴充)

JDBC 2.0 標準未定義寫入 BLOB 流,需使用廠商擴充 (以 Oracle 為例):

// 檔案 → 資料庫
File file = new File("video.mp4");
Blob blob = ...;  // 從 INSERT 空 BLOB 後 SELECT FOR UPDATE 獲取,或 createBlob()

// Oracle 擴充:獲取二進制輸出流
OutputStream out = ((oracle.sql.BLOB) blob).getBinaryOutputStream();
int bufferSize = ((oracle.sql.BLOB) blob).getBufferSize();

BufferedInputStream in = new BufferedInputStream(new FileInputStream(file), bufferSize);
byte[] buffer = new byte[bufferSize];
int count;
while ((count = in.read(buffer)) != -1) {
    out.write(buffer, 0, count);
}
out.close(); in.close();
conn.commit();

// 資料庫 → 檔案
InputStream in = blob.getBinaryStream();  // 標準 JDBC 2.0
// 同樣緩衝讀寫至 FileOutputStream

關鍵點:流式處理避免大物件載入記憶體,getBufferSize() 優化 I/O 效能。

2. 結構化類型 (STRUCT) / SQLData 介面

資料庫端定義 (Oracle)

CREATE OR REPLACE TYPE People AS OBJECT (
    NAME VARCHAR2(50),
    AGE  NUMBER
);

CREATE TABLE SAMPLES (
    SA_ID   NUMBER,
    CURSON  People,
    SAMPLE  BLOB
);

Java 端映射類實作 SQLData

public class People implements SQLData, Serializable {
    private String name;
    private int age;
    private String sql_type;  // 對應資料庫型別名稱

    public String getSQLTypeName() { return sql_type; }

    public void readSQL(SQLInput stream, String typeName) throws SQLException {
        this.sql_type = typeName;
        this.name = stream.readString();
        this.age = stream.readInt();
    }

    public void writeSQL(SQLOutput stream) throws SQLException {
        stream.writeString(name);
        stream.writeInt(age);
    }
    // getter/setter...
}

型別映射註冊與操作

// 註冊型別映射
Map typeMap = conn.getTypeMap();
typeMap.put("PEOPLE", People.class);  // 資料庫型別名稱大寫

// 寫入
String sql = "INSERT INTO SAMPLES (SA_ID, CURSON) VALUES (?, ?)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 1);
People p = new People();
p.setName("John");
p.setAge(30);
ps.setObject(2, p);  // 自動呼叫 writeSQL
ps.executeUpdate();

// 讀取
sql = "SELECT CURSON FROM SAMPLES WHERE SA_ID = 1";
ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
    People p = (People) rs.getObject(2);  // 自動呼叫 readSQL
    System.out.println(p.getName() + ", " + p.getAge());
}

3. DISTINCT 類型:內建型別別名

-- 資料庫定義
CREATE TYPE BIRTHDATE AS DATE;

-- Java 操作:直接使用對應內建型別方法
ps.setDate(1, birthDate);  // PreparedStatement.setDate
Date d = rs.getDate(1);    // ResultSet.getDate
// 因本質是 DATE,無需特殊處理

4. 陣列 (ARRAY) 與 REF 物件

API 對照

操作ResultSetPreparedStatement
BLOBgetBlob(int/String)setBlob(int, Blob)
CLOBgetClob(int/String)setClob(int, Clob)

ARRAY 特殊能力:轉為 ResultSet

Array arr = rs.getArray(1);  // 獲取陣列物件
ResultSet arrRs = arr.getResultSet();  // 作為結果集遍歷
while (arrRs.next()) {
    int index = arrRs.getInt(1);   // 陣列索引
    String value = arrRs.getString(2);  // 陣列元素值
    System.out.println("[" + index + "] = " + value);
}
// 也可指定範圍:arr.getResultSet(index, count)

REF 物件:指向結構化類型實例的引用

// 查詢包含 People 欄位的表
Ref ref = rs.getRef("CURSON");  // 獲取 REF
// REF 可傳遞給其他查詢,或透過 dereference 獲取實例 (廠商特定)

5. DataLink (JDBC 3.0):外部資料引用

// 寫入 URL 參考
URL docUrl = new URL("https://docs.example.com/spec.pdf");
ps.setURL(1, docUrl);

// 讀取
URL url = rs.getURL(1);
// 應用層決定如何解析 URL (HTTP、FTP、檔案系統等)

適用於:資料庫僅存儲參考,實際內容儲於外部內容管理系統、檔案伺服器、雲端儲存。

廠商相容性與最佳實踐

操作ResultSetPreparedStatement
ARRAYgetArray(int/String)setArray(int, Array)
REFgetRef(int/String)setRef(int, Ref)
類型OraclePostgreSQLMySQLSQL Server建議
BLOB/CLOB完整支援 + 擴充流 API完整支援 (BYTEA/TEXT)支援 (BLOB/TEXT)支援 (VARBINARY/VARCHAR(MAX))優先使用標準 API,流操作用廠商擴充
STRUCT完整 (Object Type)支援 (Composite Type)不支援支援 (UDT)跨資料庫專案慎用,或封裝適配層
ARRAY支援 (VARRAY/Nested Table)完整支援不支援支援 (Table-Valued Parameters)PostgreSQL/Oracle 專案可大膽使用
DataLink支援不支援不支援FileTable/FILESTREAM標準化程度低,建議應用層管理 URL

總結

JDBC 進階資料類型將關係資料庫能力延伸至複雜物件、大物件、結構化資料、外部引用等領域。核心掌握點:

  1. BLOB/CLOB 流式處理:大物件零記憶體複製、檔案互轉
  2. STRUCT/SQLData:物件-關係映射基礎,理解 readSQL/writeSQL 協議
  3. ARRAY/REF:陣列操作與物件引用,getResultSet() 是隱藏寶藏
  4. 廠商擴充:標準 API 覆蓋 80% 需求,關鍵 20% (流控制、效能) 需廠商 API
  5. 可移植性權衡:核心邏輯用標準 API,廠商特定功能隔離在 DAO 實作層

現代 ORM 框架 (Hibernate、MyBatis、JPA) 已封裝大部分進階類型處理,但理解底層 JDBC 機制對除錯、效能調優、跨框架整合仍具核心價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved