DB2 XML 編程之使用XML數據庫支持

瞭解 ibm® db2® 9 for Linux®, UNIX®, and windows® 新的 XML 存儲和查詢環境如何處理本系列 第 1 部分 中描述的 XML 數據模型。第 2 部分主要關注如何在應用程序體系結構中使用新的 XML 數據庫支持。

  簡介

  XML 在數據庫中的地位在過去兩年中已經發生了變化,從 “臨時工” 變成了重要成員。它不再需要改變本身來適應關係環境。它可以保持其層次化性質,同時利用關係數據庫環境的功能和穩定性。實際上,一些關係性元素已經採用某些技術讓它們看起來像 XML,以便利用層次化 XML 模型豐富的功能。

  本文討論新的 XML 存儲和查詢環境如何處理本系列 第 1 部分 中的 XML 數據模型。還要說明,在採用新的基於 XML 的應用程序開發體系結構之後,數據庫模式會變得更簡單更自然。還演示如何按照在應用程序中查詢數據的相同方式查詢數據庫中的 XML 數據。最後,討論如何結合關係數據和 XML 數據,從而同時獲得這兩個環境的優勢。

  XML 數據庫基礎

  儘管大多數主流關係數據庫都有某種 XML 支持,但是 db2 的 pureXML™ 支持要健壯和高效得多,這使它成爲試驗 XML 編程模型的理想數據庫。本文主要關注如何在應用程序體系結構中使用新的 XML 數據庫支持。

  db2 允許存儲、查詢、操作和發佈:

  •   關係數據 — sql
  •   採用 XML 形式的關係數據 — sql/XML
  •   XML 數據 — XQuery
  •   混合型數據(關係數據和 XML 數據) — sql/XML 和 XQuery

  圖 1. db2 混合型存儲

  DB2 混合型存儲

  在數據庫中存儲 XML

  關係數據庫中的 XML 支持的主要好處是,可以在同一個表中同時存儲關係數據和 XML 數據。另外,儘管 XML 在內部存儲爲層次化(樹)格式,但是它看起來像是存儲在數據庫表的單一列中(就像 CLOB 或 BLOB)。

  從第 1 部分中的數據對象可以看出,有兩個表,每個表至少有兩列。

  清單 1. 表

CREATE table CUSTOMER_TABLE (
CUSTOMERID CHARACTER (12) NOT NULL,
CUSTXML XML NOT NULL ,
CONSTRAINT CC1183665042494 PRIMARY KEY ( CUSTOMERID) )

CREATE
table PURCHASE_TABLE (
CUSTOMERID CHARACTER (12) NOT NULL ,
ITEMXML XML NOT NULL ,
CONSTRAINT CC1183665244645 FOREIGN KEY
(CUSTOMERID) REFERENCES CUSTOMER_TABLE (CUSTOMERID)
ON DELETE CASCADE ON UPDATE NO ACTION
ENFORCED ENABLE QUERY OPTIMIZATION )
 

  顯然,通過將應用程序的數據對象存儲爲 XML,關係模式大大簡化了。另外,基礎結構仍然是關係型的,這使 XML 數據能夠利用關係數據庫的實用功能,比如觸發器、約束和外鍵關係。

  因爲從邏輯上看 XML 列與 VARCHAR、CLOB 或 BLOB 列相似,所以 INSERT 語句也是相似的。


  在 Java™ 程序中執行插入的代碼也是相似的:

  清單 2. 在 Java 程序中執行插入

String insertsql= "insert into PURCHASE_TABLE values(?,?)";
PreparedStatement iStmt=connection.prepareStatement(insertsql);
File inputfile= new File(filename); //filename is the path of the XML file
long filesize=inputfile.length();
BufferedReader in = new BufferedReader(new FileReader(inputfile));
iStmt.setCharacterStream(1,in,(int)filesize);
int rc= iStmt.executeUpdate(); 

  爲了更好地瞭解混合型存儲,我們來看看 XML 數據的邏輯視圖,體會 XML 數據如何看起來像是存儲在關係數據庫表中。

  注意:儘管不同關係數據庫廠商的 XML 物理存儲技術可能不一樣,但是邏輯視圖是相似的。

  圖 2. db2 混合型存儲邏輯視圖

  DB2 混合型存儲邏輯視圖

查詢 XML

 

  在展開數據庫模式模型時,可以看到關係表和列。如果展開 XML 列,模式會從關係模型變成 XML 層次化模型。現在,您應該意識到其實有兩個模式(一個關係模式和一個 XML 模式),但是把它們當作一個整體;理解了這一點,就能夠以更自然的方式在這個統一的模式中進行導航和查詢。

  對於清單 1 所示的統一模式,如果希望獲得 CUSTOMER_TABLE 中 CUSTXML 列的數據,那麼可以在查詢中指定 CUSTXML 列的路徑作爲目標。


  這會返回 hardeep 的 CUSTXML 列中的客戶數據。

  現在,考慮如何獲得其 lastname 爲 singh 的客戶數據。在這種情況下,需要指定每個 XML 文檔的 lastname 屬性的路徑(CUSTOMER_TABLE.CUSTXML/Customer/@lastname)並檢查它是否是 singh。

  在完美的環境中,查詢應該是 Select * from CUSTOMER_TABLE where CUSTXML/Customer/@lastname='singh'。但是在真實環境中,需要用數據庫查詢引擎能夠理解的一種語法編寫查詢。數據庫領域已經引入了一種稱爲 XQuery 的新語言,可以用它查詢 XML 文檔。SQL 添加了可以理解這種語言的新函數,從而將關係和 XML 環境聯繫起來了。所以搜索姓氏爲 singh 的客戶的查詢如下:


  還可以在 Java 程序中通過參數化查詢執行這個調用:


  掌握了向 sql/XML 函數傳遞參數的語法之後,您會發現,在針對關係數據和 XML 數據的基本混合型查詢中,XML 查詢通常包含 XPath 表達式。這與在應用程序層中操作 XML 數據模型的方法非常相似(見第 1 部分),在那裏許多代碼通過對 Document Object Model(DOM)包裝器進行 XPath 調用來查詢和操作 XML 數據。

  注意:在 Viper 2 中,對傳遞給一些 sql/XML 函數的參數做了簡化。例如,在前面的查詢中,XMLExists 的 passing 子句不需要指定 CUSTXML 列。


 

  將應用程序邏輯放在數據庫中

  XQuery 提供了大多數高級語言的所有基本功能(if-then-else、for、變量、函數和算術操作符)。因此,可以將業務邏輯嵌入查詢中。另外,它還提供許多常用的 XSLT 映射,所以它不但能夠執行查詢,還能夠在數據庫中轉換 XML 輸出。

  我們仍然以第 1 部分中 Customer 示例的 XML 數據模型爲例。


 

  db2 查詢替代應用程序代碼

  我們不必在應用程序層中合併來自兩個表的 XML 數據,可以在數據庫中用一個 sql/XML 查詢實現相同的效果。這需要一個 CUSTOMER_TABLE.CUSTXML/Customer/@customerid 到 PURCHASE_TABLE.ITEMXML/Customer/@customerid 的一對多聯結。

  圖 3. 聯結兩個 XML 列

  聯結兩個 XML 列

  清單 3. 查詢兩個 XML 列

 

  對於客戶 hardeep 購買的所有商品,產生的 XML 如下:

  圖 4. 查詢結果

  查詢結果

  在上面的查詢中,必須構造外層的 Customer 元素並添加來自 CUSTXML 列數據的屬性。DB2 Viper 2(beta)支持 XQuery 更新表達式,可以修改 XML 文檔,所以不需要構造外層的 Customer 元素。可以使用來自客戶表的一個 XML 文檔,並將來自購買表的商品數據作爲子元素插入其中。

  清單 4. 針對兩個 XML 列的 Viper 2 查詢

 

  在上面的查詢中,不但搜索、獲取和合並了數據庫中存儲的 XML 文檔部分,還在產生的 XML 中添加了新元素。另外,hardeep 被隱式轉換爲 XML 類型(xs:string)。
  對比數據庫查詢和 Java 應用程序代碼

 

  如果將上面的查詢與第 1 部分中的 Java 代碼(清單 6. 重寫應用程序來使用 XML 模型)做一下對比,就會發現它們的邏輯非常相似。

  1. 從 CUSTOMER_TABLE 中選擇 Customer 信息。
  2. 構造一個 Items 元素並在 PURCHASE_TABLE 中搜索這位客戶購買的所有商品。
  3. 循環遍歷列表中的每個商品並將它們插入 Items 元素。
  4. 將 Items 元素插入 Customer 元素。

  創建存儲過程

  爲了將數據庫中的業務邏輯與應用程序代碼隔離開,一種好方法是爲這個查詢創建一個存儲過程。

  清單 5. 創建存儲過程

CREATE PROCEDURE customerItems(IN custid varchar(12))
DYNAMIC RESULT SETS 1
LANGUAGE
sql
BEGIN
DECLARE c_cur CURSOR WITH RETURN FOR

values(xmlquery('

for $Customer in
db2-fn:xmlcolumn( "CUSTOMER_TABLE.CUSTXML")/Customer

let $items:=(<Items>{

for $Customer0 in
db2-fn:xmlcolumn("PURCHASE_TABLE.ITEMXML")/Customer
where $Customer0/@customerid= $Customer/@customerid
return $Customer0/Item

}</Items>)

where $Customer/@customerid= $customerid

return
transform
copy $cust:=$Customer
modify(
do insert $items as last into $cust)
return $cust

' passing custid as "customerid" ))
OPEN c_cur;
END
 

  用存儲過程調用替代應用程序代碼

  應用程序代碼現在可以對 db2 進行存儲過程調用並將 XML 傳遞給 DOM 包裝器。第 1 部分中的 XML 數據模型的應用程序代碼(清單 6. 重寫應用程序來使用 XML 模型,2-8 行)可以簡化爲:


 

  一個更精細的示例

  現在考慮一個比較精細的場景,這個場景還要計算每個商品的保險費。爲了讓這個場景有點兒難度,保險費不但每天變動,而且隨價格變化。這意味着,不但要向查詢傳遞 customerid,還要傳遞保險費率。現在,假設您每天在保險公司提供的一個 Web 服務中查詢最新的保險費率。保險費率信息採用 XML 文檔的形式。


 
  
  可以修改前面的存儲過程來計算保險費。

  清單 6. 計算每個商品的保險費的存儲過程

CREATE PROCEDURE customerItemsWithInsurance(IN custid varchar(12), rate XML)
DYNAMIC RESULT SETS 1
LANGUAGE
sql
BEGIN
DECLARE c_cur CURSOR WITH RETURN FOR

values(xmlquery('

for $Customer in
db2-fn:xmlcolumn( "CUSTOMER_TABLE.CUSTXML")/Customer

let $items:=(
<Items>{
for $Customer0 in
db2-fn:xmlcolumn("PURCHASE_TABLE.ITEMXML")/Customer

let $insurance:=<insurance currency="{($rate//rate[@price=""]/@currency)}">
{(
if($Customer0/Item/@price > 500) then (
$Customer0/Item/@price * $rate//rate[@price=""]/@rate
)
else (

if($Customer0/Item/@price > 100) then (
$Customer0/Item/@price * $rate//rate[@price="500"]/@rate
)
else (
$Customer0/Item/@price * $rate//rate[@price="100"]/@rate
)

)
)}</insurance>

where $Customer0/@customerid= $Customer/@customerid

return
transform
copy $item:=$Customer0/Item
modify( do insert $insurance as last into $item)
return $item
}</Items>
)

where $Customer/@customerid= $customerid

return
transform
copy $cust:=$Customer
modify(do insert $items as last into $cust)
return $cust

' passing custid as "customerid", rate as "rate" ));

OPEN c_cur;
END
 

  對這個存儲過程的調用接受兩個運行時參數,customerid 和保險 XML。

  call customerItemsWithInsurance(?,?)

  顯然,在上面的示例中,如果要操作的數據庫數據是 XML 格式的,那麼可以使用 XQuery 實現比只使用 sql 時更多的業務邏輯。另外,查詢中使用的 XML 甚至不需要在數據庫中存在。因此,SQL/XML 查詢中涉及的 XML 數據可以按照層次化形式存儲在數據庫中,可以由 sql/XML 函數生成,甚至可以作爲運行時參數傳遞給查詢。數據庫和應用服務器之間的差異逐漸變得模糊了。
 優點和缺點

 

  所有新技術在剛剛出現時都會有一些問題。一些問題是由於實現還不成熟造成的,其他問題是由於開發人員還不適應變化。

  1. 儘管性能有所改進,但是仍然比不上關係數據。
  2. XQuery 是一種新語言,而且一些 sql/XML 函數的語法需要花時間適應。
  3. 有許多遺留數據採用關係格式。
  4. 最重要的是,這是一種創建業務應用程序和數據模式的新方式,它與當前的面向對象應用程序和規範化關係模式很不一樣。
  5. 能夠對這類查詢進行調試和優化的工具還不多。

  儘管存在這些缺點,但是新的模型管理數據的方式更加自然。在應用程序層和數據庫層中都按原樣維護和操作業務數據信息,而且您將第 3 部分中看到,甚至在客戶機層中也是如此。

  儘管外圍語言可能不一樣(Java、XQuery、JavaScript、PHP),但是在所有層中用來在 XML 文檔中移動的語言都是相同的(XPath)。

  即使遺留數據是關係型的,但是通過使用 Viper 2 中引入的一些 sql/XML 函數,可以輕鬆地查詢這些數據並將它們轉換爲 XML。看一下第 1 部分中的示例 “第二種情況 —— 所有數據在數據庫中存儲爲關係形式”。可以使用 Viper 2 中引入的 XMLROW 函數簡化這個查詢。


 

  還可以在關係數據和 XML 數據之間創建聯結。在這個示例場景中,如果有第三個表,其中包含購買商品的產品說明,而且這是一個關係表,那麼可以使用商品 ID 執行聯結,從而獲得購買的每種商品的產品說明。

  圖 5. 聯結關係列和 XML 列

  聯結關係列和 XML 列


 

  在 db2 9 中,可以使用 passing 子句向 sql 語句中嵌入的 XQuery 傳遞運行時參數,但是不能向 XQuery 中嵌入的 sql 傳遞參數。在 Viper 2 中,這個限制已經消除了,現在可以向 XQuery 中嵌入的關係查詢傳遞運行時變量。

  清單 7. 向 XQuery 中嵌入的 sql 傳遞運行時變量

values(xmlquery('

for $Customer0 in
db2-fn:xmlcolumn("PURCHASE_TABLE.ITEMXML")/Customer
where $Customer0/@customerid= $custid
return (
$Customer0/Item,
db2-fn:sqlquery(
''select xmlrow(details, description, weight option ROW "description")
from sqlproduct where pid= parameter(1)'', $Customer0/Item/@ID))

' passing cast( ? AS varchar(255) ) as "custid" ))
 

  因此,即使一部分數據位於關係表中,一些數據是 XML,現在都可以在 sql 查詢、XQuery 或這兩者中在 XML 數據和關係數據之間進行動態聯結。

  在某些情況下,性能可能不是大問題,因爲:

  •   能夠爲數據庫中存儲的 XML 文檔創建基於 XPath 表達式的索引。

 
  •   因爲數據庫模式更簡單,所以減少了所需的聯結數量。
  •   因爲現在可以在查詢中縮減數據,然後再把數據發送給應用程序,所以可以減少 I/O。
  •   隨時可以使用 sql/XML 函數(比如 XMLTable)將 XML 文檔中的關鍵信息提取到關係列中,併爲它們創建關係索引。
  •   可以爲 XML 文檔創建文本搜索索引。

  結束語

  XML 已經取得了穩固的地位。大多數行業和政府組織都對他們的 XML 模式做了標準化,並要求電子文檔必須符合這些模式。既然通過線路交換的 B2B 數據已經採用了 XML 格式,爲什麼不在數據庫中按原樣(pureXML)存儲這些數據呢?將數據存儲爲 XML 之後,可以使用 XQuery 和標準的 sql/XML 對它進行編制索引、查詢、檢驗、操作、轉換和更新。隨着越來越多的應用程序邏輯被放在查詢中,數據庫可以以 Web 服務和 feed 的形式公開它的存儲過程,從而成爲面向服務體系結構(SOA)環境中活躍的參與者。

<script type="text/javascript">google_ad_client = "pub-6430022987645146";google_ad_slot = "0975784993";google_ad_width = 728;google_ad_height = 90;google_cpa_choice = ""; </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>


本文轉自
http://blog.csdn.net/onlyzhangqin/archive/2008/01/15/2044617.aspx
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章