DB2 9 引入了 pureXML 技術,原生支援 XML 資料型別與 XQuery 查詢。本文將示範如何在 Java 應用程式中嵌入 XQuery,從資料表的 XML 欄位中檢索符合特定郵遞區號的客戶地址資訊。我們將採用兩種方式:透過 SQL/XML 函數 XMLQUERY 在 SQL 陳述式中嵌入 XQuery,以及直接執行獨立的 XQuery 陳述式。
所有範例操作均在 SAMPLE 資料庫中進行。首先建立 CUSTOMERS 客戶資料表,包含一個 XML 型別的 CONTACTINFO 欄位:
CREATE TABLE ADMINISTRATOR.CUSTOMERS (
CUSTOMERID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1001, INCREMENT BY 1, NO CACHE),
NAME VARCHAR(10),
AGE BIGINT,
COMPANY VARCHAR(10),
CONTACTINFO XML
);
欄位說明:
插入 3 筆測試資料,CONTACTINFO 欄位儲存的 XML 結構如下:
<?xml version="1.0"?>
<Customer xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://bogus">
<Address>
<street>5401 Julio Ave.</street>
<city>San Jose</city>
<state>CA</state>
<zip>95116</zip>
</Address>
<phone>
<work>4084630000</work>
<home>4081111111</home>
<cell>4082222222</cell>
</phone>
<fax>4087776666</fax>
<email>love2shop@yahoo.com</email>
</Customer>

XQuery 本身不支援參數占位符(Parameter Markers),因此無法直接在 PreparedStatement 中安全地傳遞動態參數。解決方案是將 XQuery 封裝在 SQL 的 XMLQUERY 函數中,透過 SQL 的 PASSING 子句將變數傳遞給 XQuery 引擎。關鍵差異如下:
db2-fn:xmlcolumn 存取 XML 欄位;嵌入 SQL 時,資料由 PASSING 子句直接傳遞。CAST(? AS INTEGER) 等方式為參數指定資料型別,確保型別安全。\")。目標:查詢居住在郵遞區號 95116 區域的客戶地址。
獨立 XQuery 寫法:
xquery for $y in db2-fn:xmlcolumn('CUSTOMERS.CONTACTINFO')/Customer/Address
where $y/zip = 95116
return $y
嵌入 SQL 的等效寫法:
SELECT XMLQUERY(
'$y/Customer/Address[zip=$z]'
PASSING CONTACTINFO AS "y",
CAST(? AS INTEGER) AS "z"
)
FROM CUSTOMERS
完整 Java 程式碼範例:
// 假設連線物件 conn 已建立
public static String getAddress(Connection conn) {
String address = null;
int zipCode = 95116;
String query = "SELECT XMLQUERY(" +
" '$y/Customer/Address[zip=$z]' " +
" PASSING CONTACTINFO AS \"y\", " +
" CAST(? AS INTEGER) AS \"z\") " +
" FROM CUSTOMERS";
try (PreparedStatement pstmt = conn.prepareStatement(query)) {
pstmt.setInt(1, zipCode);
try (ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
address = rs.getString(1);
System.out.println(address);
}
}
} catch (SQLException sqle) {
System.err.println("Error Msg: " + sqle.getMessage());
System.err.println("SQLState: " + sqle.getSQLState());
System.err.println("SQLError: " + sqle.getErrorCode());
// 實際專案中應進行交易回滾與資源釋放
}
return address;
}
DB2 9 的 JDBC 驅動程式支援直接執行 XQuery,無須包裝在 SQL 中。但需注意:此方式無法使用參數占位符,動態參數需在字串層面拼接(注意防範注入風險)。
String query = "xquery for $y in db2-fn:xmlcolumn('CUSTOMERS.CONTACTINFO')/Customer/Address " +
"where $y/zip = 95116 return $y";
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query)) {
while (rs.next()) {
System.out.println(rs.getString(1));
}
}
兩種方式均會傳回符合條件的 <Address> XML 片段:
<Address xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<street>5401 Julio Ave.</street>
<city>San Jose</city>
<state>CA</state>
<zip>95116</zip>
</Address>
PreparedStatement 与 XMLQUERY,享有參數化查詢的安全性、效能優勢(計畫重用)與型別檢查。XMLSERIALIZE、XMLTABLE 等 SQL/XML 函數進一步處理。