XML與數據庫
copyright 1999-2003 by Ronald Bourret
原作最后更新: 2003年11月
原文: www.rpbourret.com
翻譯: onestab 2004.01.23(修訂)
俄語(yǔ)版 (October, 2000)
法語(yǔ)版 (November, 2003) 法語(yǔ)版的另一個(gè)地址:Patrick Peccatte
目 錄
1.0 簡(jiǎn)介
2.0 XML是數據庫嗎?
3.0 為什么用數據庫?
4.0 數據與文件
4.1 以數據為中心的文檔
4.2 以文檔為中心的文檔
4.3 數據,文檔和數據庫
5.0 數據的存取
5.1 將文檔Schema映射到數據庫Schema
5.1.1 基于表格的映射
5.1.2 關(guān)系 - 對象映射
5.2 查詢(xún)語(yǔ)言
5.2.1 基于模板的查詢(xún)語(yǔ)言
5.2.2 基于SQL的查詢(xún)語(yǔ)言
5.2.3 XML Query 語(yǔ)言
5.3 在原生XML 數據庫中存儲數據
5.4 數據類(lèi)型, Null 值, 字符集, 及其他
5.4.1 數據類(lèi)型
5.4.2 二進(jìn)制數據
5.4.3 Null 數據
5.4.4 字符集
5.4.5 處理指令和注釋
5.4.6 標記的存儲
5.5 從關(guān)系[數據庫]Schema產(chǎn)生DTD以及相反
6.0 文件的存取
6.1 在文件系統中存儲文件
6.2 在BLOB中存儲文件
6.3 原生XML數據庫
6.3.1 什么是原生XML數據庫?
6.3.2 原生XML數據庫的架構
6.3.2.1 基于文本的原生XML數據庫
6.3.2.2 基于模型的原生XML數據庫
6.3.3 原生XML數據庫的特性
6.3.3.1 文件集
6.3.3.2 查詢(xún)語(yǔ)言
6.3.3.3 更新和刪除
6.3.3.4 事務(wù),鎖定,以及并發(fā)
6.3.3.5 應用程序接口(APIs)
6.3.3.6 雙程車(chē)票
6.3.3.7 外部數據
6.3.3.8 索引
6.3.3.9 外部實(shí)體存儲
6.3.4 規范化,引用完整性和可伸縮性
6.3.4.1 規范化
6.3.4.2 引用完整性
6.3.4.3 可伸縮性
6.4 可持久化 DOM (PDOM)
6.5 內容管理系統 CMS
7.0 XML 數據庫產(chǎn)品
8.0 相關(guān)鏈接
9.0 評論與反饋
1.0 簡(jiǎn)介 (Introduction)
本文對怎樣使用XML和數據庫進(jìn)行了總體回顧,描述了以數據為中心和以文檔文中心的文檔之間的差異如何影響其在數據庫中的應用,將XML和關(guān)系型數據庫的一起使用的常見(jiàn)用法,以及什么是原生XML數據庫和何時(shí)使用它。
2.0 XML是數據庫嗎?(Is XML a Database?)
在開(kāi)始討論XML和數據庫之前,我們先回答許多人都遇到過(guò)的問(wèn)題:“XML是數據庫嗎?”
如果僅按數據庫這個(gè)術(shù)語(yǔ)的本質(zhì)來(lái)看,XML文件就是數據庫,它是數據的集合。在許多方面看起來(lái)它和其他文件沒(méi)什么區別 -- 無(wú)論如何,每個(gè)文件都含有某種類(lèi)型的數據。作為一種“數據庫”格式,XML有一些優(yōu)勢:例如,它是自描述的(所用的標記描述了數據的結構和類(lèi)型,盡管缺乏語(yǔ)義),可交換的(portable)(Unicode),能夠以樹(shù)型或圖形結構描述數據。同樣它也有缺點(diǎn),例如,它顯得有些繁瑣,由于要對它進(jìn)行解析和文本轉換,所以數據訪(fǎng)問(wèn)速度較慢。
一個(gè)更有用的問(wèn)題就是在較為寬松的意義上,XML及其周邊技術(shù)是否可以算作“數據庫” -- 數據庫管理系統(DBMS)。答案是“在某種程度上是(sort of)”。從正面來(lái)說(shuō),XML提供了許多數據庫所具備的東西:存儲(XML文檔), 模式(DTD, XML schema,RElAX NG 等等), 查詢(xún)語(yǔ)言(XQuery, XPath, XQL, XML-QL, QUILT等等),編程接口(SAX, DOM,JDOM)等等。從反面來(lái)說(shuō),它缺少一些作為實(shí)用的數據庫所應具備的特性:高效的存儲,索引,安全,事務(wù)和數據一致性,多用戶(hù)訪(fǎng)問(wèn),觸發(fā)器,在查詢(xún)多個(gè)文件等等。
因此,盡管在數據量小、用戶(hù)少和性能要求不太高的環(huán)境下,可以將XML文檔用作數據庫,但是卻不適用于用戶(hù)量大、數據集成度高以及性能要求高的作業(yè)環(huán)境。
XML適合于用作所謂“數據庫”的一個(gè)好例子就是 .ini文件 -- 它包含應用程序的配置信息。與其寫(xiě)一個(gè)處理以逗號分隔(comma-delimited)的文件的解析器,開(kāi)發(fā)一種小型的XML語(yǔ)言并寫(xiě)一個(gè)解釋它的 SAX程序要容易的多。此外,XML允許使用嵌套的實(shí)體,而逗號分隔的文件(comma-delimited files)很難做到這點(diǎn)。然而,說(shuō)它就是數據庫還很勉強,因為它是線(xiàn)性讀寫(xiě)的,而且僅用在程序開(kāi)始和結束時(shí)。
比較適合于XML數據庫的一些復雜的數據集就是個(gè)人通訊錄(名字,電話(huà)號碼,地址等),或用于描述瀏覽器書(shū)簽以及用Napster偷來(lái)的MP3。然而,由于dBase和Access之類(lèi)的數據庫物美價(jià)廉,即使在這種情況下似乎也沒(méi)有多少理由把XML文件作為數據庫使用。XML的唯一真正好處就是數據的可交換性(portable),由于有越來(lái)越多的工具可以用來(lái)對數據庫進(jìn)行XML序列化(serializing),這一點(diǎn)好處似乎也要打些折扣。
3.0 為什么要用數據庫?(Why Use a Database?)
當你開(kāi)始考慮XML和數據庫的時(shí)候,可能首先會(huì )問(wèn)這個(gè)問(wèn)題:為什么你會(huì )先想到使用數據庫?你是否有可用的歷史數據?是否想找個(gè)地方存儲Web頁(yè)面? 是否在電子商務(wù)中使用數據庫,而XML在其中作為數據傳輸載體? 對這些問(wèn)題的回答將會(huì )極大地影響你對數據庫和中間件(如果有的話(huà))的選擇,以及如何使用所選的數據庫。
例如,你有個(gè)電子商務(wù)的應用,將XML用作數據交換。那么你的數據最好有個(gè)非常規則的結構并且可供非XML程序使用。還有,XML文檔所用的某些東西如實(shí)體和編碼對你來(lái)說(shuō)并不重要 --總之,你感興趣的是數據,而不是它在XML內如何存儲。在這種情況下,你大概需要一個(gè)關(guān)系型數據庫以及在XML和數據庫之間轉換數據的軟件。如果你的應用程序是面向對象的,你甚至還需要一個(gè)在數據庫或XML中存取這些對象的系統。
另一方面,假如你要從一些結構松散的XML文檔建立一個(gè)網(wǎng)站。你不但要管理這個(gè)網(wǎng)站,還要提供站點(diǎn)內容搜索。你的文檔看起來(lái)結構比較松散,其中的實(shí)體的使用對你來(lái)說(shuō)可能更重要,因為它們是文檔結構的重要部分。這種情況下,你也許需要一個(gè)原生XML數據庫(native XML database)或內容管理系統(content management system)。這使你可以保持文檔的物理結構,支持文件級的事務(wù)處理,以及使用XML Query語(yǔ)言進(jìn)行查詢(xún)。
4.0 數據和文檔 (Data versus Documents)
在選擇數據庫時(shí)最重要因素大概就是你想在數據庫存儲的究竟是數據還是文檔。例如,是簡(jiǎn)單地把XML當作數據庫和(可能不支持XML)應用程序之間的數據轉換工具,還是用于集成,就像XHTML和DocBook中的那樣?通常這是個(gè)偏好,但是卻非常重要,因為所有以數據為中心的(data-centric)文檔有著(zhù)許多相同的特性,所有以文檔為中心的(document-centric)也有許多相同的特性。這會(huì )影響到XML在數據庫中如何存儲。下面兩部分中我們就來(lái)考察這些特性。
(歷史背景:我在xml-dev郵件列表上第一次聽(tīng)說(shuō)data-centric和document-centric這些術(shù)語(yǔ),不知道是誰(shuí)發(fā)明的,但是我在1997的消息中發(fā)現有使用document-centric的,從1998年以后這兩個(gè)術(shù)語(yǔ)都有使用。)
4.1 以數據為中心的文檔 (Data-Centric Documents)
以數據為中心的文檔就是將XML用作數據的傳輸載體,只提供給機器消費的文檔,在此XML通常并不是絕對必要的。也就是說(shuō),對于應用程序或數據庫而言,(在某個(gè)時(shí)間段內)數據是否以XML文檔的形式存儲并不重要。以數據為中心的文檔的例子有銷(xiāo)售訂單、航班時(shí)刻表、科研數據及股市匯率。
以數據為中心的文檔的特點(diǎn)是結構相當規整,數據粒度精細(fine-grained data)(即最小的獨立數據單位只存在于PCDATA元素或屬性這一級別),很少或沒(méi)有混合內容。除非在對文檔進(jìn)行驗證的時(shí)候,同級元素或PCDATA的出現次序一般來(lái)說(shuō)并不重要。
以數據為中心的文檔中的這類(lèi)數據可以來(lái)自數據庫(此時(shí)要輸入給XML)或在數據庫之外(此時(shí)要將其存入數據庫)。前者的一個(gè)例子就是關(guān)系數據庫現存的大量數據;而從測量系統采集并轉化為XML的科研數據就是后者的例子。
例如,下面的銷(xiāo)售訂單就是以數據為中心的:
<SalesOrder SONumber="12345">
<Customer CustNumber="543">
<CustName>ABC Industries</CustName>
<Street>123 Main St.</Street>
<City>Chicago</City>
<State>IL</State>
<PostCode>60609</PostCode>
</Customer>
<OrderDate>981215</OrderDate>
<Item ItemNumber="1">
<Part PartNumber="123">
<Description>
<p><b>Turkey wrench:</b><br />
Stainless steel, one-piece construction,
lifetime guarantee.</p>
</Description>
<Price>9.95</Price>
</Part>
<Quantity>10</Quantity>
</Item>
<Item ItemNumber="2">
<Part PartNumber="456">
<Description>
<p><b>Stuffing separator:<b><br />
Aluminum, one-year guarantee.</p>
</Description>
<Price>13.27</Price>
</Part>
<Quantity>5</Quantity>
</Item>
</SalesOrder>除了像銷(xiāo)售訂單這種顯而易見(jiàn)的以數據為中心的文檔之外,許多以文本為主的(prose- rich)文檔也可以是以數據為中心的。例如,Amazon.com用來(lái)顯示書(shū)籍信息的一個(gè)頁(yè)面。盡管頁(yè)面上大部分內容都是文本,這些文本的結構是非常規則的,許多都和其它書(shū)籍的描述相同,每個(gè)頁(yè)面特有的文本并不很多。這樣,就可以從數據庫中取出書(shū)籍的相關(guān)資料,轉換為簡(jiǎn)單的、以數據為中心的XML文檔,再用XSL樣式表生成頁(yè)面。一般來(lái)說(shuō),那些用數據庫中的數據填充模板,動(dòng)態(tài)生成HTML文件的網(wǎng)站都可以轉而使用一系列以數據為中心的XML文檔和XSL樣式表。
例如,下面是個(gè)描述航班信息的文檔:
<FlightInfo>
<Airline>ABC Airways</Airline> provides <Count>three</Count>
non-stop flights daily from <Origin>Dallas</Origin> to
<Destination>Fort Worth</Destination>. Departure times are
<Departure>09:15</Departure>, <Departure>11:15</Departure>,
and <Departure>13:15</Departure>. Arrival times are minutes later.
</FlightInfo>從下面的XML文件和一個(gè)簡(jiǎn)單的樣式表中創(chuàng )建這個(gè)文檔:
<Flights>
<Airline>ABC Airways</Airline>
<Origin>Dallas</Origin>
<Destination>Fort Worth</Destination>
<Flight>
<Departure>09:15</Departure>
<Arrival>09:16</Arrival>
</Flight>
<Flight>
<Departure>11:15</Departure>
<Arrival>11:16</Arrival>
</Flight>
<Flight>
<Departure>13:15</Departure>
<Arrival>13:16</Arrival>
</Flight>
</Flights>4.2 以文檔為中心的文檔 (Document-Centric Documents)
以文檔為中心的文檔通常是供人消費的。例如書(shū)籍、email、廣告以及幾乎所有人工寫(xiě)成的XHTML文件。其特性為結構不太或根本不規則、數據粒度大(larger grained data)(最小的獨立數據單位可能存在于包含混合內容的元素甚至整個(gè)文檔本身),混合內容多。同級元素或PCDATA出現的次序一般來(lái)說(shuō)總是非常重要的。
以文檔為中心的文檔通常是以XML手工寫(xiě)成,或從其他格式(如RTF, PDF, SGML)轉換到XML,與以數據為中心的文檔不同,它們的來(lái)源通常不是數據庫。(將數據插入到模板而得到的文檔是以數據為中心的;更多信息請看4.1節末尾部分)。將各種格式轉換為XML的軟件信息,請參閱XML軟件相關(guān)鏈接。
例如,下面這個(gè)產(chǎn)品說(shuō)明是以文檔為中心的:
<Product>
<Intro>
The <ProductName>Turkey Wrench</ProductName> from <Developer>Full
Fabrication Labs, Inc.</Developer> is <Summary>like a monkey wrench,
but not as big.</Summary>
</Intro>
<Description>
<Para>The turkey wrench, which comes in <i>both right- and left-
handed versions (skyhook optional)</i>, is made of the <b>finest
stainless steel</b>. The Readi-grip rubberized handle quickly adapts
to your hands, even in the greasiest situations. Adjustment is
possible through a variety of custom dials.</Para>
<Para>You can:</Para>
<List>
<Item><Link URL="Order.html">Order your own turkey wrench</Link></Item>
<Item><Link URL="Wrenches.htm">Read more about wrenches</Link></Item>
<Item><Link URL="Catalog.zip">Download the catalog</Link></Item>
</List>
<Para>The turkey wrench costs <b>just $19.99</b> and, if you
order now, comes with a <b>hand-crafted shrimp hammer</b> as a
bonus gift.</Para>
</Description>
</Product>
4.3 數據、文檔和數據庫(Data, Documents, and Databases)
在現實(shí)當中,以數據為中心和以文檔為中心的文檔之間的差別不一定很明顯。例如,另一種以數據為中心的文檔比如發(fā)票,可能含有大粒度的、結構不規則的數據比如零件說(shuō)明;另一種以文檔文中心的文件如用戶(hù)手冊,可能包含細粒度的結構規則的數據(通常為元數據)比如作者和修訂日期。其它例子包括法律和醫學(xué)文書(shū),雖然以松散的形式寫(xiě)成但是卻包含離散的數據塊例如日期、名稱(chēng)和操作程序,出于法規的原因通常要以完整的文件形式存儲。
除此之外,弄清文件的這兩種特點(diǎn)有助于選擇數據庫的類(lèi)型。一般來(lái)說(shuō),將數據存儲于傳統的數據庫,例如關(guān)系型,面向對象型或層次型數據庫。這可由第三方的中間件完成或由數據庫本身提供內在支持。對于后者,該數據庫被稱(chēng)作支持XML的(XML-enabled)。文檔可被存儲在原生(native)XML數據庫(專(zhuān)為存儲XML而設計的數據庫)或內容管理系統(建在原生XML數據庫之上專(zhuān)門(mén)用來(lái)管理文檔的程序)。
這些原則并不是絕對的。如果對XML特有的功能不很看重,數據,特別是半結構化的數據可以存儲在原生XML數據庫,文檔也可以存儲到傳統數據庫。何況傳統數據庫與原生XML數據庫之間的界限越來(lái)越模糊,傳統數據庫增加了原生XML的能力,而原生XML數據庫增加了對文檔存儲在外部(通常為關(guān)系型)數據庫的支持。
本文剩下的部分就有關(guān)數據(第5節)和文檔(第6節)的存儲和讀取的策略與問(wèn)題展開(kāi)討論。關(guān)于最新的XML數據庫產(chǎn)品,請見(jiàn)XML數據庫產(chǎn)品。
5.0 數據的存取(Storing and Retrieving Data)
為了在XML文件和數據庫之間交換數據,必須將XML文件的schema(DTD,XML Schema, RELAX NG等)映射到數據庫的schema。用于數據轉換的軟件位于這種映射的上層。該軟件可以使用XML Query語(yǔ)言(如XPath,XQuery,或其他專(zhuān)用語(yǔ)言)或簡(jiǎn)單地按照映射(SELECT * FROM Table的XML對應形式)轉換數據。
對于后者,文檔的結構必須完全符合映射所要求的結構。由于通常不易做到這點(diǎn),使用這種策略的產(chǎn)品一般要和XSLT一起使用。在數據轉換到數據庫之前,先將文件按照映射所要求的結構進(jìn)行轉換,然后轉存數據。相應地,數據從數據庫中取出以后,結果文件要被轉換成應用程序所需的結構。
5.1 映射[XML]文件Schema到數據庫Schema (Mapping Document Schemas to Database Schemas)
文件schema到數據庫schema的映射是在元素類(lèi)型、屬性和文本上進(jìn)行的。這時(shí)幾乎總是忽略物理結構(例如實(shí)體、CDATA部分及編碼信息)及某些邏輯結構(如處理指令、注釋以及元素和PCDATA在父元素內出現的順序)。這樣做是自然而然的,因為數據庫和應用程序只需關(guān)心XML文件中的數據。例如,在上述的銷(xiāo)售訂單中,客戶(hù)代號是在CDATA部分,還是外部實(shí)體中,或直接就是PCDATA并不重要,同樣,客戶(hù)代號出現在訂貨日期之前或之后也無(wú)關(guān)緊要。
這種方法的一個(gè)后果是能否保證文件有“往返車(chē)票” -- 將文件中的數據存入數據庫后,又從數據庫中的數據重新構建文件,得到的文件往往和原來(lái)的文件不同(哪怕從最簡(jiǎn)單的角度來(lái)講)。這種情形是否可以接受取決于你的要求,在選擇軟件時(shí)要考慮到這一點(diǎn)。
將一個(gè)XML文件的schema映射到數據庫的schema有兩種方法:基于表格的映射和對象-關(guān)系映射。
5.1.1 基于表格的映射 (Table-Based Mapping)
許多轉換XML到數據庫的中間軟件都采用基于表格的映射。它把XML文件看作一個(gè)(或一組)表格,也就是說(shuō),XML文件的結構必須是下面這種樣子,如果只是單一表格的話(huà),就不再需要<database>元素和其他<table>元素:
<database>
<table>
<row>
<column1>...</column1>
<column2>...</column2>
...
</row>
<row>
...
</row>
...
</table>
<table>
...
</table>
...
</database>
根據所用軟件的不同,可以將各字段數據以子元素的形式或以屬性的形式存儲,同樣也可以指定這些元素或屬性的名字。此外,采用基于表格映射方式的軟件還可能允許在文件開(kāi)始的地方包含表格或各字段的元數據,或者將其作為各表格或元素的屬性。注意這里所說(shuō)的“表格”是泛指的表格。當將數據從數據庫中轉到XML文件時(shí),“表格”可以是任何結果集,反之,“表格”可以是普通的表格或可更新的視圖。
基于表格的映射對存取關(guān)系型數據比較適用,比如在兩個(gè)關(guān)系型數據庫之間轉換數據。其明顯不足就是不適于格式不符的XML文件。
5.1.2 對象-關(guān)系映射 (Object-Relational Mapping)
所有支持XML的關(guān)系型數據庫和某些中間件都可以使用對象-關(guān)系的映射方式。它將XML文件中的數據視為特定的對象樹(shù)的模型。在這個(gè)模型中,元素及其類(lèi)型、元素內容或混合內容(復合元素類(lèi)型)通常被視為類(lèi)。只具有PCDATA內容的元素(簡(jiǎn)單元素類(lèi)型)、屬性以及PCDATA都被當作簡(jiǎn)單屬性。然后通過(guò)傳統的對象-關(guān)系映射技術(shù)或 SQL 3的對象視圖將該模型映射到關(guān)系型數據庫。也就是說(shuō),類(lèi)被映射到表格,簡(jiǎn)單屬性被映射到字段,而值為對象屬性被映射為成對的主鍵/外鍵(primary key/foreign key)。
(所謂“對象-關(guān)系映射”有些名不副實(shí)。因為對象樹(shù)可以被直接映射到面向對象型和層次型數據庫,然而,但是由于大多數使用這種映射方式的主流產(chǎn)品使用的其實(shí)是關(guān)系型數據庫,所以“對象-關(guān)系映射”也就廣為人知。)
我們在理解這種映射所用的對象模型的時(shí)候要知道,這個(gè)對象模型不是文件對象模型(DOM)。所有XML文件的DOM都是一樣的,而上述描述文件數據的模型對于每個(gè)DTD所定義的XML文件都不一樣,例如,上述銷(xiāo)售訂單的模型是一個(gè)由四個(gè)類(lèi)所組成的對象樹(shù)--SalesOrder, Customer, Item, 和Part, 如下圖所示:
SalesOrder
/ | \
Customer Item Item
| |
Part Part
在由同一個(gè)文件產(chǎn)生的DOM中,對象樹(shù)的組成是元素、屬性和文本:
元素 --- 屬性
(SalesOrder) (SONumber)
____/ / \ \_____
/ / \ \
元素 文本 元素 元素
(Customer) (OrderDate) (Item) (Item)
| | |
etc. etc. etc.
模型中的對象是否被實(shí)例化要取決于所用的軟件。有些軟件允許依據模型產(chǎn)生類(lèi),然后可以在程序中使用由這些類(lèi)所產(chǎn)生的對象。在這些產(chǎn)品中,數據是在XML文件 - 對象 -數據庫之間傳遞的。其他產(chǎn)品是直接在XML文件和數據庫之間進(jìn)行數據轉換的,對象只是作為這種過(guò)程的可視化幫助工具。生成這些中間對象是否有用完全取決于你的應用程序。
(根據Sun的 Java Architecture for XML Binding,XML文件與對象的綁定通常被稱(chēng)為XML數據綁定(XML data binding),有些產(chǎn)品支持XML數據綁定,其中許多還可以在對象和數據庫之間進(jìn)行數據交換,更多的信息,請看 XML數據綁定相關(guān)資源 XML Data Binding Resources.)
各種產(chǎn)品對對象-關(guān)系映射的具體支持各不相同。例如:
所有產(chǎn)品都支持從復合元素類(lèi)型到類(lèi),以及從簡(jiǎn)單元素類(lèi)型和屬性(attributes)到[類(lèi)的]屬性(properties)的映射。
所有(?)產(chǎn)品都允許你指定是否將根元素映射到對象模型或數據庫。如果你想在同一個(gè)XML文檔中存儲多個(gè)頂級對象時(shí),這個(gè)包裝元素(wrapper element)就顯得有用了。例如,如果你想在同一個(gè)XML文件中存儲多個(gè)銷(xiāo)售訂單,就必須把它們包裝在一個(gè)根元素內。
當使用基于表格的映射的XML文件有多個(gè)表格組成時(shí),這個(gè)包裝元素就相當于<database>元素,他的存在只是為了滿(mǎn)足 XML 文件只能有一個(gè)根元素的要求。少數產(chǎn)品允許你就像指定包裝元素那樣,在較低的層次上指定[某些元素是否被映射 -譯注]。
大多數產(chǎn)品允許你說(shuō)明將[對象的]屬性(properties)映射到XML文件中的屬性(attribute)還是子元素。某些產(chǎn)品還允許你混合使用屬性和子元素,其他的只允許你使用兩者之一。
大多數產(chǎn)品允許XML文件和數據庫的名字可以不同。少數產(chǎn)品要求必須使用相同的名字。
大多數產(chǎn)品允許你說(shuō)明子元素在父元素中的出現次序,盡管如此,仍然不可能建立多個(gè)內容模型。幸好對于大多數以數據為中心的文檔而言,所支持的內容模型已經(jīng)足夠。(當文件需要驗證時(shí),子元素的次序才顯得相當重要。)
某些產(chǎn)品允許你將復合元素類(lèi)型映射到簡(jiǎn)單屬性 (properties)。當某個(gè)元素包含混合內容(例如銷(xiāo)售訂單中的< Description>元素)時(shí),這點(diǎn)相當有用。盡管<Description>元素像XHTML一樣包含子元素和文本,但最好還是將這個(gè)description視為單個(gè)屬性,而不是把它分成許多碎塊。
支持混合內容中的PCDATA映射的產(chǎn)品不多。
關(guān)于對象-關(guān)系型映射的詳細描述,請看第三部分“將DTD映射到數據庫”。
5.2 查詢(xún)語(yǔ)言(Query Languages)
許多產(chǎn)品都是按照它們所建的模型直接進(jìn)行數據交換。由于XML文件的結構和數據庫的結構一般不同,這些產(chǎn)品一般都使用了或包括了XSLT樣式表。這就允許用戶(hù)在數據被交換到數據庫之前(或相反)根據模型規定的格式對文件進(jìn)行轉換。由于XSLT處理的代價(jià)較高,某些產(chǎn)品只提供有限幾種這樣的轉換。
這個(gè)問(wèn)題的長(cháng)久解決方案就是設計一種可以返回XML[文件]的查詢(xún)語(yǔ)言。目前來(lái)看(2002年11月),大多數這種語(yǔ)言都依賴(lài)于在模板中嵌入 SELECT 語(yǔ)句。到 XQuery 最后定稿時(shí)這個(gè)局面有望得到改變,正如主流的數據庫產(chǎn)品提供商已經(jīng)做的那樣。不幸的是,幾乎所有的XML查詢(xún)語(yǔ)言(包括 XQuery1.0 和 SQL/XML的最初發(fā)布版本)對文件都是只讀的,所以短期來(lái)說(shuō),最需要的是能夠插入、更新、刪除數據的手段。(從長(cháng)遠來(lái)看,XQuery 和 SQL/XML 將會(huì )增加這種功能。)
5.2.1 基于模板的查詢(xún) (Template-Based Query)
大多數從數據庫讀取XML的查詢(xún)語(yǔ)言是基于模板的,這些語(yǔ)言并沒(méi)有預先定義XML文件和數據庫之間的映射,相反,是將SELECT語(yǔ)句嵌入到模板中,由數據交換軟件對結果進(jìn)行處理。例如,下面的模板(并不是真正產(chǎn)品中的)使用包含了SELECT語(yǔ)句和$column-name值的< SelectStmt>元素來(lái)決定將結果放在何處。
<?xml version="1.0"?>
<FlightInfo>
<Introduction>The following flights have available seats:</Introduction>
<SelectStmt>SELECT Airline, FltNumber, Depart, Arrive FROM Flights</SelectStmt>
<Flight>
<Airline>$Airline</Airline>
<FltNumber>$FltNumber</FltNumber>
<Depart>$Depart</Depart>
<Arrive>$Arrive</Arrive>
</Flight>
<Conclusion>We hope one of these meets your needs</Conclusion>
</FlightInfo>
這個(gè)模板處理之后的結果可能是:
<?xml version="1.0"?>
<FlightInfo>
<Introduction>The following flights have available seats:</Introduction>
<Flights>
<Flight>
<Airline>ACME</Airline>
<FltNumber>123</FltNumber>
<Depart>Dec 12, 1998 13:43</Depart>
<Arrive>Dec 13, 1998 01:21</Arrive>
</Flight>
...
</Flights>
<Conclusion>We hope one of these meets your needs.</Conclusion>
</FlightInfo>
基于模板的查詢(xún)語(yǔ)言非常靈活。盡管各個(gè)產(chǎn)品的功能不盡相同,但有一些共同特性:
可以將返回結果放在輸出文件中的任何地方,包括作為后續SELECT語(yǔ)句的參數。
可由程序構建 for 循環(huán)和 if 語(yǔ)句。
可以定義變量和函數。
可通過(guò)HTTP參數實(shí)現SELECT語(yǔ)句的參數化(parameterization)。
從關(guān)系數據庫中將數據轉換到XML文件時(shí),幾乎一定要用到基于模板的查詢(xún)語(yǔ)言。雖然有些產(chǎn)品也將基于模板的查詢(xún)語(yǔ)言用于XML文件到關(guān)系數據庫的數據轉換,這時(shí)所用的并不是完整的模板語(yǔ)言。相反,他們使用的是上面所述的基于表格的映射。
5.2.2 基于SQL的查詢(xún)語(yǔ)言 (SQL-Based Query Languages)
基于SQL的查詢(xún)語(yǔ)言使用的是經(jīng)過(guò)修改的SELECT語(yǔ)句,[查詢(xún)]結果被轉換為XML。目前已經(jīng)有一些私有的基于SQL的語(yǔ)言可用。通過(guò)簡(jiǎn)單地使用嵌套的SELECT語(yǔ)句,就可直接轉換成符合對象 - 關(guān)系映射的嵌套的XML?;蛘呤褂肧QL 3的對象視圖也可直接轉換成XML。最后還可使用 OUTER UNION 語(yǔ)句和特殊標記來(lái)決定怎樣將結果轉換成 XML。
除了這些私有語(yǔ)言以外,2000年一些公司聯(lián)合提出了 SQL 的 XML 擴展標準,現在已經(jīng)成為被稱(chēng)為 SQL/XML 的 ISO SQL 標準的一部分;最終可望于2003年得到批準。 SQL/XML 引入了一種 XML 數據類(lèi)型,并且為 SQL 增加了幾個(gè)函數,可以從關(guān)系型數據構造 XML 元素和屬性。
例如,下面的查詢(xún)
SELECT Orders.SONumber,
XMLELEMENT(NAME "Order",
XMLATTRIBUTES(Orders.SONumber AS SONumber),
XMLELEMENT(NAME "Date", Orders.Date),
XMLELEMENT(NAME "Customer", Orders.Customer)) AS xmldocument
FROM Orders
構造了具有兩個(gè)字段的結果集。第一個(gè)字段為銷(xiāo)售訂單號,第二個(gè)字段為一個(gè) XML 文件。每一行有一個(gè) XML 文件,它來(lái)自 Orders 表中相應的數據。例如,從訂單號 123 生成的 XML 文件是:
<Order SONumber="123">
<Date>10/29/02</Date>
<Customer>Gallagher Industries</Customer>
</Order>
在網(wǎng)上很難找到有關(guān) SQL/XML 的資料。關(guān)于其介紹和(可能)過(guò)時(shí)的一些資料,請參考 SQLX Group 網(wǎng)站 。 SQL/XML 標準的拷貝可從 sqlstandards.org 的FTP 目錄得到(ftp://sqlstandards.org/SC32/WG3/Progression_Documents/Informal_working_drafts/)。你要找的文件名應當是WD5-14-xml-yyyy-mm.pdf 或 wd5-14-xml-yyyy-mm.pdf, 這里 yyyy-mm 是標準的年月。比如2003年11月的最新標準的文件名為 WD5-14-xml-2003-09.pdf。注意 sqlstandards.org 的 FTP 站點(diǎn)經(jīng)常宕機,你可能要不斷嘗試才行。另外還可以在 Google 上搜索 XMLFOREST 或 XMLAGG。
5.2.3 XML Query Languages
基于模板和基于SQL的查詢(xún)語(yǔ)言只能用于關(guān)系數據庫,與此不同,XML查詢(xún)語(yǔ)言可用于任何XML文檔。為了把它用于關(guān)系數據庫,必須把數據庫中的數據看作XML的模型,這樣才能對虛擬的XML文件進(jìn)行查詢(xún)。
對于XQuery,基于表格的映射或對象-關(guān)系型映射都可以使用。當使用基于表格的映射時(shí),各個(gè)表格被視為單獨的文件,像SQL中的一樣, 這些表格的結合(joints)則在查詢(xún)[語(yǔ)句]本身中指明。如果使用的是對象-關(guān)系型映射,各個(gè)表格的層次被當作單個(gè)文件,而[表格的]結合在映射中說(shuō)明。對于大多數關(guān)系數據庫而言,似乎基于表格的映射更為常用,這是因為它的實(shí)現似乎更簡(jiǎn)單些,SQL的用戶(hù)對此也更為熟悉。
如果使用XPath在多個(gè)表格中進(jìn)行查詢(xún),就必須使用對象-關(guān)系映射,這是因為XPath不支持多個(gè)文檔的聯(lián)合。因此,如果使用基于表格的映射,也許每次只對一個(gè)表格進(jìn)行查詢(xún)最好。
5.3 原生XML數據庫的數據存儲(Storing Data in a Native XML Database)
還可以將XML文件中的數據存儲在原生XML數據庫(native XML database)中。這么做有幾個(gè)理由。首先,當你的數據是半結構化的數據時(shí)。也就是說(shuō),它的結構是普通的,但是如果將其映射到關(guān)系數據庫,結果是要么出現大量空值(null)的字段,要么表格的數量過(guò)多,浪費空間或效率低下。雖然半結構化的數據可存儲到面向對象的或層次型數據庫中,你還可以選擇將它以XML文件的形式存儲于原生XML數據庫。
將數據存儲在原生XML數據庫中的第二個(gè)理由是讀出速度。根據XML數據庫存儲數據的物理方式的不同,數據的讀出速度可以做到比關(guān)系型數據庫[的讀取速度]快得多。其原因是,原生XML數據庫對整個(gè)文件一起進(jìn)行物理存儲,和[表示]文件各個(gè)部分的物理(而不是邏輯)指針可采用同一存儲策略。這就可以不使用連接(joins)或只使用物理連接讀取文件,無(wú)論哪種情況都比關(guān)系型數據庫所用的邏輯聯(lián)結要快。
以上述銷(xiāo)售訂單文件為例。在關(guān)系型數據庫中,它可能被存為四個(gè)表格 -- SalesOrders, Items, Customers, 和 Parts -- 讀取文件時(shí)需要將這些表格結合起來(lái)。在原生XML數據庫中,整個(gè)文件可被存儲在磁盤(pán)的一個(gè)地方,在讀取文件或其片斷時(shí)只需要一次查找和一次讀取操作。關(guān)系數據庫在讀取數據時(shí)則需要四次查找以及至少四次讀取操作。
這樣做的一個(gè)明顯缺點(diǎn)就是,只有數據的讀取順序和寫(xiě)入磁盤(pán)的順序相同時(shí),才可以提高速度。如果你想要的數據視圖不同,比如只想要客戶(hù)及其訂單列表,性能可能比關(guān)系數據庫更差。所以,如果你的應用中是單個(gè)數據視圖為主,為了提高性能,才可以考慮將數據存儲到原生XML數據庫。
將數據存儲在原生XML數據庫中的第三個(gè)理由是你想利用XML的獨有特性,如執行XML查詢(xún)。由于今天以數據為中心的應用幾乎沒(méi)有這樣做的,而且關(guān)系數據庫正在逐步支持XML查詢(xún)語(yǔ)言,這個(gè)理由越來(lái)越不充分。
將數據存儲在原生XML數據庫中的一個(gè)問(wèn)題是,大多數原生數據庫只能以XML[的形式]返回數據。(支持元素和屬性到應用程序變量綁定的只是少數)。如果你的應用程序需要另一種數據格式(很有可能),使用數據之前必須先解析XML。對本地的應用程序而言顯然是個(gè)缺點(diǎn),而這種前期準備在(比如)ODBC中就不存在。對于將XML作為數據載體使用的分布式應用程序而言,這個(gè)問(wèn)題不很?chē)乐?,因為不管用的是哪種數據庫,這種前期工作必須要有。
5.4 數據類(lèi)型,空值,字符集,諸如此類(lèi) (Data Types, Null values,Character Sets, and All That Stuff)
本節將就在傳統數據庫中存儲XML文件數據的相關(guān)問(wèn)題展開(kāi)討論。(有關(guān)數據類(lèi)型和二進(jìn)制數據存儲的討論同樣適用于原生XML數據庫)總的說(shuō)來(lái),你無(wú)法選擇數據交換軟件解決這些問(wèn)題的方式。然而,你應當明白這些問(wèn)題確實(shí)存在,這樣會(huì )有助于你選擇軟件。
5.4.1 數據類(lèi)型 Data Types
如果單從字面上講,XML并不支持任何數據類(lèi)型。除了非解析實(shí)體,XML文件中的所有數據都是文本,盡管它可能表示日期或整數等其他類(lèi)型。一般來(lái)說(shuō),數據交換軟件負責把(XML文件中的)文本轉換成(數據庫中的)其他數據類(lèi)型,反之亦然。
至于軟件如何確定該進(jìn)行怎樣的轉換各不相同,常見(jiàn)的有兩種方法。第一種方法是軟件根據數據庫模型來(lái)確定數據類(lèi)型,因為它在運行時(shí)總是可用的。(而XML模型在運行時(shí)就不一定有,甚至根本就不存在)。第二種方法就是由用戶(hù)明確指定數據類(lèi)型,比如映射信息。它可以由用戶(hù)寫(xiě)出,或者自動(dòng)從數據庫模型或XML 模型中產(chǎn)生。
類(lèi)型轉換時(shí)的另一個(gè)問(wèn)題是,究竟能夠識別(從 XML 轉換)或創(chuàng )建什么文本格式。大多數情況下,能夠被識別為特定數據類(lèi)型的文本格式數目很有限,比如某個(gè)JDBC驅動(dòng)程序支持單一的、特定的格式。日期看起來(lái)最容易出問(wèn)題,因為它的格式可能非常多。而數字在各種語(yǔ)言中的格式也不盡相同,也有可能出問(wèn)題。
5.4.2 二進(jìn)制數據 (Binary Data)
二進(jìn)制數據在XML文件中的存儲方法一般有三種:非解析實(shí)體和Base64編碼(一種 MIME 編碼方式,將二進(jìn)制數據映射到US-ASCII碼的一個(gè)子集[0-9a-zA-Z+/] - 見(jiàn)RFC 2045 );十六進(jìn)制編碼(每二進(jìn)制字節用兩個(gè)十六進(jìn)制字符[0-9a-fA-F]表示)以及非解析實(shí)體(二進(jìn)制數據存儲在與該XML分離的物理實(shí)體內)。
二進(jìn)制數據的最大問(wèn)題在于數據轉換產(chǎn)品對它的支持不夠,所以要檢查你的軟件是否支持。另一個(gè)問(wèn)題是,大部分(全部?)數據轉換產(chǎn)品都不存儲符號和實(shí)體聲明。這樣,將 XML 中的數據轉換到數據庫中時(shí),與某些實(shí)體對應的符號就會(huì )丟失。(關(guān)于符號的更多信息詳見(jiàn) XML 標準的 4.7 部分)。
5.4.3 空數據 (Null Data)
在數據庫術(shù)語(yǔ)中,空數據(null data)意味著(zhù)沒(méi)有數據。這和值為0的數字或長(cháng)度為零的字符串區別非常大。例如,假設你收集到的是氣象數據,如果溫度計不能工作,則數據庫中存儲的就是null而不是0,否則情況就完全不同了。
XML也支持這種空數據的概念(通過(guò)可選(optional)元素或屬性)。如果一個(gè)可選元素或屬性的值為空,就不會(huì )包含在文件內。而在數據庫中,值為零長(cháng)度字符串的屬性和空元素并不是null:它們的值為零長(cháng)度的字符串。
當你將XML文檔的結構映射到數據庫(或反過(guò)來(lái))時(shí),你當特別留意,可選元素類(lèi)型或[空值]屬性會(huì )被映射到允許空值的字段(nullable columns),反之亦然。如果不是這樣的話(huà),可能會(huì )產(chǎn)生插入錯誤(當轉換數據到數據庫時(shí))或非法文件錯誤(從數據庫中取出數據時(shí))。
與數據庫專(zhuān)業(yè)相比,XML社區對null含義的表示法更為自由-- 特別是許多XML用戶(hù)都認為零長(cháng)度字符串的屬性和空元素是“空(null)”的,所以你應該檢查一下你的軟件是如何處理這種情況的。有些軟件為用戶(hù)提供了選擇,可以定義XML中如何表示"null",以及支持XML Schema中的 xsi:null屬性。
5.4.4 字符集 (Character Sets)
根據定義,除了某些控制字符,XML文件可包含任何Unicode字符。不過(guò),許多數據庫對Unicode的支持很有限或根本就不支持,而且需要特殊的配置才能處理非ASCII字符。如果你的文件包含非ASCII字符,要確保你的數據庫及數據轉換軟件對這些字符是否支持及如何支持的。
5.4.5 處理指令和注釋 (Processing Instructions and Comments)
處理指令和注釋并不是XML文檔“數據”的一部分,大多數(全部?)數據轉換軟件都不能處理它們。問(wèn)題在于這些東西可能出現在XML文檔中的任何地方,所以不容易進(jìn)行基于表格或對象-關(guān)系型映射。(一個(gè)明顯行不通的方案是為這些處理指令和注釋建立一個(gè)表格,在其他表格加上指向這個(gè)表格的外部鍵(foreign key),每當處理別的表格時(shí),就檢查這些表)。所以大多數數據轉換軟件會(huì )簡(jiǎn)單地忽略它們。如果處理指令和注釋對你相當重要,就要檢查所用軟件對此能否處理及處理方法?;蛘呖梢钥紤]使用原生XML數據庫(native XML database)。
5.4.6 對標記的存儲 (Storing Markup)
正如5.1.2 一節所提到的, 有時(shí)候需要在數據庫中存儲混合內容的元素而無(wú)須進(jìn)一步解析。這時(shí),標記被存儲為標記字符(markup is stored with markup characters)。然而,問(wèn)題出現在如何存儲那些不作為標記使用的標記字符。在XML文檔中,這些是以 lt, gt, amp, quot 和 apos 實(shí)體存儲的。在數據庫中也可這么做。例如,下面的description:
<description>
<b>Confusing example:</b> <foo/>
</description>
在數據庫中可存為:
<b>Confusing example:</b> <foo/>
這樣做的一個(gè)問(wèn)題是一些非XML查詢(xún)語(yǔ)言,如SQL不會(huì )在表中搜尋標記和實(shí)體的用法并將其正確翻譯。這樣,如果你打算用SQL來(lái)搜索字符串“<foo/>”,你應當知道實(shí)際的搜索字符串是“<foo/>”。
另外,如果實(shí)體引用被擴展了,數據轉換軟件無(wú)法區別標記和實(shí)體。例如,如果上述例子在數據庫中按照下面的形式存儲,則軟件就無(wú)法知道<b> , </b> 和<foo/>到底是標記還是文本。
<b>Confusing example:</b> <foo/>解決這個(gè)問(wèn)題的長(cháng)久之計就是支持XML的數據庫(XML-aware database),在那里,對真正的標記和看起來(lái)很像標記的東西的處理方式是不同的。非XML應用程序處理XML時(shí),總是會(huì )出現這種問(wèn)題。
5.5 從關(guān)系[數據庫]Schema產(chǎn)生DTD或相反 (Generating DTDs from Relational Schema and Vice Versa)
在XML文件與數據庫之間進(jìn)行數據轉換時(shí)經(jīng)常遇到的一個(gè)問(wèn)題是如何從數據庫schema產(chǎn)生DTD或相反。在解釋如何做之前,必須指出這是設計階段的任務(wù)。其原因是大多數以數據為中心的應用以及幾乎所有的盤(pán)點(diǎn)應用軟件(vertical applications)都是在已知的DTD或數據庫模型上工作的,因此,不會(huì )在運行時(shí)產(chǎn)生schema。再者,如下所述,schema的產(chǎn)生過(guò)程不十分嚴格。如果應用程序需要在數據庫中隨機存放XML文件,則應考慮使用使用原生XML數據庫,而不是在運行時(shí)產(chǎn)生schema.
從DTD產(chǎn)生關(guān)系模型(或相反)的最簡(jiǎn)單方法就是直接借助于對象-關(guān)系映射,它有幾個(gè)可選特性。對于面向對象的數據庫也有相似的途徑。(關(guān)于每種方法的逐步演示,請看Mapping DTDs to Databases.)。
從DTD產(chǎn)生關(guān)系模型:
對每個(gè)復合數據類(lèi)型, 創(chuàng )建一個(gè)表格和主鍵字段
對每個(gè)混合內容的元素類(lèi)型,另外建一個(gè)表用來(lái)存儲PCDATA,通過(guò)其父表格的主鍵與父表格相連。
對該種數據類(lèi)型的每個(gè)單值屬性,以及每個(gè)單次出現簡(jiǎn)單子元素在表中建一個(gè)字段。如果子元素或屬性是可選的,將該字段設置為可為空值的字段(nullable)。
對每個(gè)多值屬性(multi-valued attribute)和每個(gè)多次出現的簡(jiǎn)單元素,單獨創(chuàng )建一個(gè)表,通過(guò)其父表格的主鍵與父表格相連
對每個(gè)復合類(lèi)型的字元素,通過(guò)其父表格的主鍵將父表與該子元素類(lèi)型的表相連。
從關(guān)系[數據庫]模型產(chǎn)生DTD:
為每個(gè)表創(chuàng )建一種元素類(lèi)型。
對表中的每個(gè)數據(非鍵)字段以及主鍵字段,在元素類(lèi)型上增加一個(gè)屬性或在內容模型上增加一個(gè)PCDADA型的字元素。
對于每個(gè)引用該主鍵的表格,在內容模型上增加一個(gè)子元素,繼續遞歸處理表格。
對于每個(gè)外來(lái)鍵,在內容模型上增加一個(gè)子元素,繼續遞歸處理外來(lái)鍵表格。
這些過(guò)程有一些不足,其中許多都可手工解決,比如名稱(chēng)沖突及指定字段數據類(lèi)型和長(cháng)度。(DTD不包含數據類(lèi)型信息,所以不可能預知數據庫中的數據類(lèi)型。注意,從XML Schema文件可以預測數據類(lèi)型和長(cháng)度。)
更加嚴重的問(wèn)題是,XML文件所用的數據“模型”通常和數據庫中所用的高效率的模型不同,(實(shí)際上更為復雜)。請看如下XML片斷:
<Customer>
<Name>ABC Industries</Name>
<Address>
<Street>123 Main St.</Street>
<City>Fooville</City>
<State>CA</State>
<Country>USA</Country>
<PostCode>95041</PostCode>
</Address>
</Customer>
從DTD產(chǎn)生關(guān)系模型的一般過(guò)程來(lái)看,通常會(huì )產(chǎn)生兩個(gè)表:一個(gè)是customers,另一個(gè)是addresses。然而,大多數情況下把 address存放在customer表中更為合理。
<Address>元素就是包裝元素(wrapper element)的典型例子。采用包裝元素的原因有二:首先,這種結構使得文檔更容易理解;其次,它可作為一種數據類(lèi)型使用。例如,可以將<Address>元素傳給一個(gè)例程,該例程可以將所有地址轉換為Address對象,不管它出現在哪里。
雖然包裝元素在XML中很有用,但被映射到數據庫中的時(shí)候會(huì )增加額外的結構,很容易出問(wèn)題。因此,在產(chǎn)生關(guān)系模型之前,一般應將其從DTD中除去。由于DTD一般是不允許改變的,而在映射是又不包含包裝元素,所以往往會(huì )導致實(shí)際文檔與數據轉換軟件所要求的文檔不匹配。對此可以在運行時(shí)轉換文件(比如使用XSLT):數據被轉到數據庫之前去掉包裝元素,轉出后在加上它。
盡管有這些不足,上述步驟還是為DTD和關(guān)系模型之間的轉換提供了一個(gè)起點(diǎn),對于大型系統尤為如此。
6.0 文件的存取 (Storing and Retrieving Documents)
XML文件的存儲方式有兩大類(lèi):存儲于文件系統或作為BLOB存儲于關(guān)系數據庫以獲得有限的XML功能,或者將其存儲于原生XML數據庫。
6.1 將文件存儲于文件系統 (Storing Documents in the File System)
如果你的文件比較簡(jiǎn)單,數量不多,最簡(jiǎn)便的方法就是存儲于文件系統。以后可以使用grep之類(lèi)的工具進(jìn)行查詢(xún)或sed來(lái)修改。(對XML文件進(jìn)行全文檢索顯然不夠精確,比如很難區分文本和標記,而且無(wú)法理解實(shí)體的用法。然而,對于小型系統,這還是可以接受的)如果你想實(shí)現簡(jiǎn)單的事務(wù)管理(transaction control),可以將文件放在諸如CVS或RCS等版本管理系統中。
6.2 將文件存儲于BLOB (Storing Documents in BLOBs)
另一種較為復雜的方法就是將文件存儲于關(guān)系數據庫中的BLOB。這就利用了數據庫的一些優(yōu)點(diǎn):事務(wù)管理、安全、多用戶(hù)訪(fǎng)問(wèn)等。此外許多關(guān)系數據庫提供的檢索工具可以進(jìn)行全文檢索、近似檢索、同義詞檢索和模糊檢索。其中某些工具將會(huì )支持XML,這樣就可消除將XML文件作為純文本檢索所帶來(lái)的問(wèn)題。
如果以BLOB的形式存儲XML文件,即使數據庫不支持對XML的檢索,你也很容易實(shí)現自己的XML檢索。方法之一是創(chuàng )建兩個(gè)表:索引表(DB2中的side table)和文件表。文件表包含一個(gè)主鍵和一個(gè)存儲文件的BLOB字段,索引表內有一個(gè)已建立索引值字段以及一個(gè)外來(lái)鍵指向文件表中的主鍵。
文件被存在數據庫中之后,就可以搜索所有已建索引的元素和屬性實(shí)例。每個(gè)實(shí)例及文件的主鍵都存于索引表中。這樣已建立索引的字段使應用程序可以快速檢索某個(gè)元素或屬性值并獲取相應的文件。
舉例來(lái)說(shuō),假如你有一些符合下列DTD的文件,希望建立作者的索引:
<!ELEMENT Brochure (Title, Author, Content)>
<!ELEMENT Title (#PCDATA)>
<!ELEMENT Author (#PCDATA)>
<!ELEMENT Content (%Inline;)> <!-- Inline entity from XHTML -->你可以用下表來(lái)存儲它:
Authors Brochures
---------------------- ---------
Author VARCHAR(50) BrochureID INTEGER
BrochureID INTEGER Brochure LONGVARCHAR假如你在數據庫中插入了一個(gè)brochure,程序就會(huì )在Brochures表中插入該 brochure,然后尋找<Author>元素,將它的值和brochure ID存入Authors表中。以后就可通過(guò)簡(jiǎn)單的SELECT語(yǔ)句得到某個(gè)Author的所有brochure。比如想得到author為Chen的所有 brochure,就可以執行下面的語(yǔ)句:
SELECT Brochure
FROM Brochures
WHERE BrochureID IN (SELECT BrochureID FROM Authors WHERE Author=‘Chen‘)
更復雜的索引表可包含四個(gè)字段:元素類(lèi)型或屬性名、(元素或屬性)類(lèi)型、值和文件ID。這樣就可在一個(gè)表中存放多個(gè)標記[文件], 并按名字、類(lèi)型和值建立索引。寫(xiě)個(gè)操作這個(gè)表的SAX程序應該不是件難事。
6.3 原生XML數據庫 (Native XML Databases)
上述的簡(jiǎn)單系統所提供的功能如果不能滿(mǎn)足你的需要,你可以考慮使用原生XML數據庫(native XML database)。原生XML 數據庫是專(zhuān)用于存儲XML文件的數據庫。和其他數據庫一樣,它支持事務(wù)管理、安全、多用戶(hù)訪(fǎng)問(wèn)、編程API和查詢(xún)語(yǔ)言等。與其它數據庫的唯一區別就是其內部模型是基于XML的,而不是其他的模型--如關(guān)系模型。
顯然原生XML數據庫最適于存儲以文檔為中心的文件。這是由于原生XML數據庫保留了文件[元素?]順序、處理指令、注釋、CDATA塊以及實(shí)體引用等,而支持XML的數據庫(XML-enabled database)無(wú)法做到。此外,原生數據庫支持XML查詢(xún)語(yǔ)言,你可以對它提這樣的問(wèn)題:“找出所有第三段內包含粗體字的文件”,用SQL顯然很難進(jìn)行這樣的查詢(xún)。
原生XML數據庫還適用于存儲那些“天然格式”為XML的文件,而不管這些文件包含什么內容。例如,電子商務(wù)系統消息所用的XML文件。盡管這些文件可能是以數據為中心的,而作為消息來(lái)說(shuō)它們的天然格式是XML。這樣當它們被存入消息隊列后,建立在原生XML數據庫上的消息隊列使用起來(lái)更為方便。原生XML數據庫保留了XML的特性比如XML查詢(xún)語(yǔ)言,通常能更快地取出整條消息。Web cache是這類(lèi)應用的另一個(gè)例子。
原生XML數據庫的其他用途是存儲半結構化數據、在某種特定情形下提高存取速度以及存儲沒(méi)有DTD的文件(良構的文件)。前兩種已經(jīng)在5.3 原生XML數據庫的數據存儲中敘述過(guò)。而后一種用非XML的數據庫是做不好的。也就是說(shuō),原生XML數據庫無(wú)須事先配置即可接受和存儲任何XML文件。將XML文件中的數據轉換到關(guān)系型或面向對象型數據庫必須首先建立映射和數據庫模型。無(wú)須事先配置對于搜索引擎之類(lèi)的應用程序來(lái)說(shuō)是有利的,因為沒(méi)有任何DTD能適用于所有搜索文檔。
6.3.1 什么是原生數據庫(Native XML Database)?
"native XML database" 這個(gè)術(shù)語(yǔ)首先在 Software AG 為 Tamino 所做的營(yíng)銷(xiāo)宣傳中露面。也許由于它的成功,后來(lái)這個(gè)術(shù)語(yǔ)在同類(lèi)產(chǎn)品的開(kāi)發(fā)商那里成了通用叫法。它是一個(gè)營(yíng)銷(xiāo)術(shù)語(yǔ),從來(lái)沒(méi)有正式的技術(shù)定義,這是它的一個(gè)缺陷。
有一個(gè)接近的定義(出自XML:DB mailing list的一個(gè)成員)這樣定義原生XML數據庫(native XML database):
它為 XML 文檔(而不是文檔中的數據)定義了一個(gè)(邏輯)模型,并根據該模型存取文件。這個(gè)模型至少應包括元素、屬性、PCDATA 和文件順序。這種模型的例子有XPath數據模型、XML Infoset 以及 DOM 所用的模型和SAX 1.0的事件。
它以 XML 文件作為其基本(邏輯)存儲單位,正如關(guān)系數據庫以表中的行作為基本(邏輯)存儲單位。
它對底層的物理存儲模型模型沒(méi)有特殊要求。例如,它可以建在關(guān)系型、層次型或面向對象的數據庫之上,或者使用專(zhuān)用的存儲格式,比如索引或壓縮文件。
該定義的第一部分與其他類(lèi)型數據庫的定義相似,都是關(guān)于數據庫所用的模型的。不過(guò),原生 XML 數據庫所能存儲的信息比模型中定義的多。例如,它可支持基于XPath 數據模型的查詢(xún),但所用的存儲格式是純文本。CDATA 部分和實(shí)體用法也可存儲在數據庫中,但是模型中沒(méi)有包括。
定義的第二個(gè)部分是說(shuō)原生數據庫的基本存儲單位是 XML 文件??雌饋?lái)似乎也可存儲 XML 文件片斷,但幾乎所有的原生 XML 數據庫都是以文件方式存儲的。
(基本存儲單位就是可以容納一份數據的最低級的上下文 (context),相當于關(guān)系數據庫中的行。它的存在并不妨礙以更小的數據單位來(lái)讀取數據,比如文件片斷或個(gè)別元素,同樣也不影響將不同文件中的片斷進(jìn)行組合。從關(guān)系數據庫的術(shù)語(yǔ)來(lái)講,相當于數據雖然以行的形式存放,并不意味著(zhù)無(wú)法讀取某個(gè)字段的值,或從現有的數據行創(chuàng )建新一行數據。)
該定義的第三部分講的是底層的數據存儲格式并不重要。確實(shí)如此,正如關(guān)系數據庫所使用的物理存儲格式與數據庫是不是關(guān)系型之間毫無(wú)關(guān)系。
6.3.2 原生XML數據庫的結構 (Native XML Database Architectures)
原生XML數據庫的結構可分為兩大類(lèi):基于文本的和基于模型的。
6.3.2.1 基于文本的原生XML數據庫(Text-Based Native XML Databases)
基于文本的原生XML數據庫將XML作為文本存儲。它可以是文件系統中的文件、關(guān)系數據庫中的BLOB或特定的文件格式。(事實(shí)上,就其能力來(lái)說(shuō),一個(gè)增加了支持CLOB(Character Large Object)字段的XML處理功能的關(guān)系數據庫也可以是原生XML數據庫了。)
索引對所有基于文本的原生XML數據庫來(lái)說(shuō)都是一樣的,它可以使查詢(xún)引擎很方便地跳到XML文件內的任何地方。這就可以大大提高數據庫存取文件或文件片斷的速度。這是因為數據庫只需進(jìn)行一次檢索、磁頭定位,再假如所讀的文件在磁盤(pán)上是連續[存儲]的話(huà),只需一次讀盤(pán)就可讀出整個(gè)文件或文件片斷。相反,如果像關(guān)系數據庫或基于模型的原生XML數據庫那樣,文件由各個(gè)部分組合而成,就必須要進(jìn)行多次查找定位和多次讀盤(pán)動(dòng)作。
從這個(gè)意義上講,基于文本的原生XML數據庫與層次結構的數據庫很相似,當存取預先定義好層次的數據的時(shí)候,它比關(guān)系數據庫更勝一籌。和層次結構的數據庫一樣,當以其他形式比如轉置層次存取數據時(shí),原生XML數據庫也會(huì )遇到麻煩。這個(gè)問(wèn)題的嚴重程度尚未可知,很多關(guān)系數據庫都使用邏輯指針,使相同復雜度的查詢(xún)以相同的速度完成。由此看來(lái)這確實(shí)是個(gè)問(wèn)題。
6.3.2.2 基于模型的原生XML數據庫 (Model-Based Native XML Databases)
第二類(lèi)原生XML數據庫是基于模型的原生XML數據庫。它們不是用純文本存儲文件,而是根據文件構造一個(gè)內部模型并存儲這個(gè)模型。至于模型究竟怎樣存儲取決于數據庫。有些數據庫將該模型存儲于關(guān)系型和面向對象的數據庫中,例如在關(guān)系型數據庫中存儲DOM時(shí),就會(huì )有元素、屬性、PCDATA、實(shí)體、實(shí)體引用等表格。其他數據庫使用了專(zhuān)為這種模型作了優(yōu)化的專(zhuān)有存儲格式。
(Mark Birbeck 在 1998年12月的 XML-L 郵件列表中描述了一個(gè)建立在關(guān)系型數據庫上的簡(jiǎn)單的、基于 模型的原生 XML 數據庫系統,該系統用了5個(gè)表 - 屬性定義、元素/屬性關(guān)聯(lián)、內容模型定義、屬性值、元素值 (PCDATA 或指向其它元素的指針),以及只包含元素、屬性、文本和文件順序的模型。參見(jiàn)標題為 "Record ends, Mixed content, and storing XML documents on relational database" 和 "storing XML documents on relational database"的信件。)
建立在其他數據庫之上的基于模型的原生XML數據庫的文件存取性能與這些數據庫相似,原因顯而易見(jiàn):其存取要依賴(lài)這些數據庫。但是這個(gè)數據庫,特別是建立在其他數據庫之上的原生XML數據庫的設計有很大的變化余地。例如直接以 DOM 方式進(jìn)行對象-關(guān)系映射的數據庫系統在獲取節點(diǎn)的子元素時(shí)必須單獨執行 SELECT 語(yǔ)句。另一方面,這種數據庫大多對存取模型和軟件作了優(yōu)化。例如 Richard Edwards 在 system for storing the DOM in a relational database一文中曾經(jīng)描述只用一個(gè)SELECT語(yǔ)句就可獲取任意文件片斷(或整個(gè)文件)。
使用專(zhuān)用存儲格式的基于模型的原生XML數據庫如果以文件的存儲順序讀取文件,其性能與基于文本的原生XML數據庫相似。這是因為這種數據庫大多在節點(diǎn)間使用了物理指針,這樣其讀取性能和讀取文本差不多。(究竟哪個(gè)快一些要取決于數據格式。如果返回文本格式,顯然基于文本的系統要快一些;如果希望返回的是DOM,假如該模型很容易映射到DOM,則基于模型的系統更快。)
與基于文本的原生XML數據庫一樣,如果數據的讀取順序和存儲順序不同,基于模型的原生XML數據庫很容易出現性能上的問(wèn)題。這兩種類(lèi)型的數據庫到底哪個(gè)快一些仍不是很清楚。
6.3.3 原生XML數據庫的特性 (Features of Native XML Databases)
本節簡(jiǎn)單討論原生XML數據庫的一些特性,有助于大致了解其現狀和未來(lái)。
6.3.3.1 文件集 (Document Collections)
許多原生XML數據庫都支持集合(collection)的概念,其作用相當于關(guān)系數據庫中的表和文件系統中的文件夾,例如你想在原生XML數據庫中存儲銷(xiāo)售訂單,就可以定義一個(gè)銷(xiāo)售訂單的集合,這樣對銷(xiāo)售訂單的查詢(xún)就限于這個(gè)集合內的文件。
作為另一個(gè)例子,假設你想把公司的所有產(chǎn)品的說(shuō)明書(shū)存儲在原生XML數據庫中,在這種情形下,你要先定義一個(gè)層次結構。比如,為每種產(chǎn)品定義一個(gè)集合,并在其中為每種產(chǎn)品說(shuō)明書(shū)的每個(gè)章節都指定一個(gè)集合。
這些集合是否被允許嵌套取決于所用的數據庫。
6.3.3.2 查詢(xún)語(yǔ)言 (Query Languages)
幾乎所有的原生XML數據庫都至少支持一種查詢(xún)語(yǔ)言。最常用的有 XPath (對多個(gè)文件的查詢(xún)作了擴充)和 XQL,以及很多專(zhuān)有的查詢(xún)語(yǔ)言。在考慮原生XML數據庫時(shí)應當確定其查詢(xún)語(yǔ)言是否滿(mǎn)足你的需要,比如從全文檢索到多個(gè)文件片斷的合并。
將來(lái)大多數原生XML數據庫大概都要支持W3C的XQuery。
6.3.3.3 更新和刪除 (Updates and Deletes)
原生XML數據庫對文件的更新和刪除方式有許多,從簡(jiǎn)單的替換或刪除現有文件,到修改當前活動(dòng)的 DOM 樹(shù),以及用于指定如何修改文件片斷的語(yǔ)言。通常每種能修改文件片斷的產(chǎn)品都有自己的語(yǔ)言,盡管有幾種產(chǎn)品支持XML:DBInitiative 的XUpdate語(yǔ)言。至于文件的更新正是業(yè)界和學(xué)術(shù)界的探討領(lǐng)域,近期似乎沒(méi)有完整的解決方案[2002年2月]。
6.3.3.4 事務(wù)、鎖定和并發(fā) (Transactions, Locking, and Concurrency)
基本上所有的原生XML數據庫都支持事務(wù)處理(當然也應支持后退[rollback])。但是,鎖定通常是對整個(gè)文檔的而不是對文件片斷的,所以多用戶(hù)并發(fā)性[的支持]相對較低。問(wèn)題的大小取決于應用程序以及“文件”的構成。
例如用戶(hù)手冊分成幾個(gè)章節,每個(gè)章節都是一個(gè)文件,這時(shí)并發(fā)問(wèn)題就小一些,因為兩個(gè)作者同時(shí)對同一章節進(jìn)行更新的情況不大可能發(fā)生。而另一方面,如果整個(gè)公司的客戶(hù)數據都放在同一個(gè)文件中(糟糕的設計),文件級的鎖定很容易造成災難性的后果。
將來(lái),大多數的原生數據庫應該會(huì )提供文件片斷級的鎖定。
6.3.3.5 應用程序接口 (Application Programming Interfaces ,APIs)
幾乎所有原生數據庫都提供編程接口A(yíng)PI。這種API很像ODBC,并提供有連接到數據庫、瀏覽元數據、執行查詢(xún)和返回結果的方法 (methods)。返回結果通常是XML字符串、DOM樹(shù)、返回文檔的SAX解析器或XMLReader。如果查詢(xún)返回結果是多個(gè)文檔的話(huà),通常都會(huì )提供例舉(iterating)這些結果的方法。
對以數據為中心的應用來(lái)說(shuō)比較有趣的特性是將應用程序變量與返回文檔的特定元素或屬性相關(guān)聯(lián)的能力。這就免除了應用程序為構件內部數據對象而不得不對文檔進(jìn)行解析的工作,隨著(zhù)XML數據綁定技術(shù)的應用越來(lái)越多,看起來(lái)這個(gè)特性會(huì )得到廣泛支持。
雖然大多數原生XML數據庫都提供有自己的API,但是XML:DB.org已經(jīng)開(kāi)發(fā)出一種與供應商無(wú)關(guān)的XML數據庫API (vendor-neutral XML database API),許多原生XML數據庫已經(jīng)支持它,而且有些非原生的[XML]數據庫也可能支持。不管這個(gè)或其他的API是否會(huì )成為工業(yè)標準,此類(lèi)API的廣泛采用最終是不可避免的。
大多數原生數據庫還有將查詢(xún)結果通過(guò) HTTP 返回的能力。
6.3.3.6 “往返車(chē)票”(Round-Tripping)
原生XML數據庫的一個(gè)重要特性是它可以為XML文檔提供了“往返車(chē)票(round-trip)”。就是說(shuō)你可以將XML文件存放在原生XML數據庫中,而且再取回“同樣的”文件。對于以文檔為中心的應用程序來(lái)說(shuō)非常重要,因為CDATA部分、實(shí)體用法、注釋和處理指令是這些文檔不可缺少的組成部分。特別是對于法律和醫學(xué)文件,按規定這些文檔必須要保持原樣。
(對于以數據為中心的應用來(lái)說(shuō),由于它主要關(guān)心的是元素、屬性、文本以及層次順序,這種“往返車(chē)票”顯得不是很重要。能夠在XML文件和數據庫之間交換數據的軟件都可以處理這些往返問(wèn)題,如果同級元素的順序對以數據為中心的應用程序來(lái)說(shuō)很重要,在有限幾種情況下也可以保留這種順序。但是由于它[指一般的交換軟件--譯者注]一般不保留兄弟元素的順序,也不確保原樣保持處理指令、注釋以及物理結構(實(shí)體引用、CDATA等等),所以不適于以文檔為中心的應用。)
所有原生XML數據庫都能夠在元素、屬性、CDATA和文件順序的級別上為文件提供“往返車(chē)票”,至于究竟能達到什么程度取決于數據庫。一般來(lái)說(shuō),基于文本的原生XML數據庫能夠原樣存取XML文件,而基于模型的原生XML數據庫只能在文件模型的級別上原樣存取XML文件。對于特別小的文檔模型,意味著(zhù)比普通的XML原樣存取的級別低。
由于你的應用程序要求決定了應當在哪個(gè)級別原樣存取,所以對原生XML數據庫的選擇余地可能很大,也可能很小。
6.3.3.7 外部數據 (Remote Data)
某些原生XML數據庫可包含有外部數據,這些外部數據來(lái)自存儲在數據庫中的文檔。通常這些數據通過(guò)ODBC、OLE DB或JDBC從關(guān)系數據中取出,模型可以是基于表格的或對象-關(guān)系型映射。原生XML數據庫決定了這些數據是不是即時(shí)的(live)--即原生XML數據庫中文檔的更新是否在外部數據庫中反映出來(lái)。大多數原生XML數據庫大概最終都會(huì )支持即時(shí)的外部數據。
6.3.3.8 索引 (Indexes)
幾乎所有的原生XML數據庫都支持元素和屬性的索引。像非XML數據庫一樣,索引用于提高檢索速度。
6.3.3.9 外部實(shí)體存儲 (External Entity Storage)
XML文檔存儲時(shí)的一個(gè)棘手問(wèn)題就是怎樣處理外部實(shí)體。也就是說(shuō),應當將其展開(kāi),把它的值存儲在文件中,還是保留實(shí)體引用原封不動(dòng)?這個(gè)問(wèn)題沒(méi)有統一的答案。
例如,假設文檔中包含一個(gè)外部實(shí)體用來(lái)調用一個(gè)當前天氣報告的CGI程序。如果將這個(gè)文件用于提供天氣預報的網(wǎng)頁(yè),那么將這個(gè)實(shí)體展開(kāi)就是錯誤的,因為網(wǎng)頁(yè)中提供的不是即時(shí)的數據。相反,如果文件是氣象歷史資料的一部分,那么不展開(kāi)它反而是不對的,否則文件總是含有當前的數據而不是歷史資料了。
再看另外一個(gè)例子,假設一個(gè)產(chǎn)品手冊只包含指向手冊中其他章節的外部實(shí)體引用。如果這些章節又被其他文件(比如該產(chǎn)品的另一種型號的手冊)使用,那么展開(kāi)這些引用就不對了,因為這會(huì )造成同一個(gè)章節有多份拷貝。
我不知道原生XML數據庫如何處理這個(gè)問(wèn)題。最理想的當然是允許你根據不同情況指定是否展開(kāi)外部實(shí)體引用。
6.3.4 規范化,引用完整性和可伸縮性 (Normalization, Referential Integrity, and Scalability)
對許多人,特別是有關(guān)系型數據庫背景的人來(lái)說(shuō),由原生XML數據庫引發(fā)出不少爭論,特別是圍繞數據的存儲方面(相對于文檔而言)。這里我們就來(lái)討論這些話(huà)題。
6.3.4.1 規范化 (Normalization)
規范化指的是數據庫模型的設計當中要保證每一份數據只能存儲一次。規范化有幾個(gè)好處,例如可以減少磁盤(pán)空間占用,消除可能的數據不一致性。這是關(guān)系型數據庫技術(shù)的基礎之一,也是人們在討論原生XML數據庫的數據存儲時(shí)的熱點(diǎn)問(wèn)題。
在進(jìn)一步討論規范性之前,需要指出對許多以文檔為中心的文件這不是大問(wèn)題。例如有一些描述公司產(chǎn)品信息的文件,通常各個(gè)文件的公用數據很少--比如版權聲明、公司地址和電話(huà)號碼、產(chǎn)品標志等等,其數量相對來(lái)說(shuō)太小了,幾乎沒(méi)有人考慮它的存儲規范性。(但是,其他種類(lèi)的文檔可能有許多重疊內容,有必要進(jìn)行規范化)。
與關(guān)系型數據庫一樣,原生XML數據庫并不要求你一定要規范你的數據,用原生XML數據庫你也很容易設計出一個(gè)糟糕的存儲結構。所以在將文件存入原生XML數據庫之前,你應仔細考慮文檔的結構。(與關(guān)系型數據庫相比,原生XML數據庫在這點(diǎn)有些優(yōu)勢。因為原生XML數據庫沒(méi)有數據庫模式,你可以同時(shí)以多種模式存儲相似的文件,不過(guò)為了簡(jiǎn)化事務(wù)處理,你可能需要重新設計查詢(xún)并轉換你的文件(這相對并不重要))
原生XML數據庫的規范化和關(guān)系型數據庫的規范化差不多一樣:你的文檔的設計要保證不會(huì )有重復數據。兩者的不同在于XML支持多值屬性而(大多數)關(guān)系型數據庫不支持。這樣就有可能以一種在關(guān)系型數據庫中無(wú)法實(shí)現的方式來(lái)“規范”原生XML數據庫的數據。
例如銷(xiāo)售訂單,它含有頭信息比如訂單編號、日期和客戶(hù)代碼,還有具體項目如零件號、數量和總價(jià)。在關(guān)系型數據庫中,頭信息和具體項目必須存在于不同的表內。而在原生XML數據庫中,這些信息可以存儲在同一個(gè)文件內,不會(huì )產(chǎn)生冗余,因為XML與生俱來(lái)就支持一個(gè)父元素內包含多個(gè)子元素。
不幸的是,現實(shí)當中的規范化可沒(méi)這么簡(jiǎn)單。例如你想要銷(xiāo)售訂單包含客戶(hù)信息如合同名稱(chēng)、收貨和付款地址,該怎樣做? 你有兩種選擇:第一,你可以在銷(xiāo)售訂單中復制一份客戶(hù)信息,結果帶來(lái)數據冗余和其他問(wèn)題;第二,你可以單獨存儲客戶(hù)信息,在銷(xiāo)售訂單中提供一個(gè)指向客戶(hù)信息文件的XLink,或者在查詢(xún)時(shí)再將這兩個(gè)文件連接起來(lái)。這就要求對XLink的支持(雖然正在計劃,但大多并不支持)或者查詢(xún)語(yǔ)言要支持聯(lián)合[joins](同樣并不總能如愿)。
在實(shí)踐當中答案尚不明確。實(shí)際當中出于性能的考慮,數據并不總是規范的,所以有一些不規范的XML數據并不像初看起來(lái)那么糟糕,不過(guò)你必須做出抉擇。如果你存儲的是以文檔為中心的文件并且在相當程度上做到了規范化,比如將章節或過(guò)程單獨存儲并將它們連接起來(lái)創(chuàng )建最終用戶(hù)所用的文件,那么原生XML數據庫可能就是一個(gè)不錯的解決方案,尤其是它能提供別的數據庫中所沒(méi)有的特性比如XML查詢(xún)語(yǔ)言。如果你要存儲的文件是以數據為中心的,而原生XML數據庫能夠改進(jìn)應用程序的性能,或者它提供的半結構化數據存儲,而在別的數據庫中是無(wú)法實(shí)現的,你也應當用原生XML數據庫。如果你只不過(guò)想在原生XML數據庫內實(shí)現一個(gè)關(guān)系型數據庫,你就應該反思一下,為什么不把關(guān)系型數據庫列為首選。
6.3.4.2 引用完整性 (Referential Integrity)
與規范性密切相關(guān)的是引用完整性(referential integrity)。引用完整性即相關(guān)數據的[引用]指針的有效性,是保持數據庫數據一致性的必要條件。如果你的銷(xiāo)售訂單含有一個(gè)客戶(hù)代碼,而相應的客戶(hù)信息并不存在,這對你沒(méi)什么好處。發(fā)貨部門(mén)不知道往哪里發(fā)貨,而財務(wù)部門(mén)不知道給哪里寄發(fā)票。
在關(guān)系型數據庫中,引用完整性意味著(zhù)確保外部鍵指向合法的主鍵,也就是說(shuō),對每個(gè)外部鍵都要檢查相應的主鍵記錄。在原生XML數據庫中,引用完整性意味著(zhù)XLink或其他專(zhuān)有鏈接機制指向合法的文件或文件片斷。
XML 文件中的指針有多種形式:ID/IDREF 屬性,key/keyref 域(在 XML Schema 中定義),XLink 以及各種私有機制。后者包括語(yǔ)言相關(guān)的“referencing”元素和屬性,例如 XML Schema 中 <element>元素的 ref 屬性,以及特定數據庫的鏈接機制。而語(yǔ)言相關(guān)的“referencing” 元素比較普遍,數據庫特定的鏈接機制較為少見(jiàn)。
原生 XML 數據庫的引用完整性可分為兩大類(lèi):內部指針(同一文件內的指針)的完整性和外部指針(不同文件之間的指針)的完整性。使用非標準機制實(shí)現的內部指針的引用完整性一向難以達到,因為原生 XML 數據庫無(wú)法識別此類(lèi)指針。以標準機制比如 ID/IDREF 或 key/keyref 實(shí)現的內部引用完整性至少可通過(guò)驗證獲得部分支持。
之所以說(shuō)部分支持,是因為大多數原生 XML 數據庫僅在將文件存入數據庫時(shí)才進(jìn)行驗證。這樣,如果更新發(fā)生在文件級 - 即刪除和替換文件,驗證已足以確保內部指針的完整性。但是如果更新發(fā)生在節點(diǎn)一級 -即插入、修改和刪除節點(diǎn),則數據庫必須執行額外的工作(比如校驗所有的變化)來(lái)確保內部指針的引用完整性。支持該功能的原生 XML 數據庫極少(如果有的話(huà))。
對外部指針的引用完整性(據我所知)仍未有支持,甚至支持外部指針的數據庫都很罕見(jiàn)。假如某個(gè)外部指針指向了數據庫中的其他資源,沒(méi)有理由不保證其完整性,但如果指向了數據庫之外的資源,這種保證的缺乏尚有情可原。例如,某個(gè)文件內的一個(gè) XLink 指向了外部網(wǎng)站的某個(gè)文件,數據庫顯然無(wú)法知道后者是否存在,因而也就無(wú)法保證該 XLink 的完整性。
將來(lái),許多原生XML數據庫大致都會(huì )以標準的機制支持內部指針的引用完整性。許多原生 XML數據庫大約都會(huì )在某種程度上支持外部指針,以及支持指向同一個(gè)數據庫中的資源的外部指針的引用完整性。而在目前,多數情況下還有賴(lài)于應用程序保證(內部或外部)指針的完整性。
6.3.4.3 可伸縮性 (Scalability)
可伸縮性完全不是我的所長(cháng),所以下面大多都是我的推測??偟膩?lái)說(shuō),我想原生XML數據庫的可伸縮性在某些環(huán)境下會(huì )非常好,而其他場(chǎng)合下可能非常糟糕。
與層次型和關(guān)系型數據庫類(lèi)似,原生XML數據庫也使用索引來(lái)查找數據。這就意味著(zhù)文件(或文件片斷)的查找只與索引的大小有關(guān),而與文件的大小和數量無(wú)關(guān),因而原生XML數據庫定位文件開(kāi)始的速度和其他使用同一種索引技術(shù)的數據庫一樣。由此看來(lái),原生XML數據庫的可伸縮性和其他數據庫一樣。
與層次型數據庫相同而與關(guān)系型數據庫不同的是,許多原生XML數據庫用物理方法鏈接相關(guān)數據。特別是基于文本的原生XML數據庫用物理的方法對相關(guān)數據分組,使用專(zhuān)用存儲格式的基于模型的原生XML數據庫通常使用物理指針來(lái)對相關(guān)數據分組。(建立在關(guān)系數據庫之上基于模型的原生XML數據庫使用的是邏輯鏈接。)
由于物理鏈接比邏輯鏈接速度快,原生XML數據庫和層次型數據庫一樣,數據的讀出速度比關(guān)系型數據庫快得多。因此,從數據的讀取方面來(lái)看,它應具有同樣的可伸縮性。事實(shí)上,在數據的讀取能力上XML數據庫比關(guān)系型數據庫甚至更好,因為可伸縮性與初次索引查找有關(guān),而不是關(guān)系型數據庫所用的多次查找。(需要指出,關(guān)系型數據庫也以集簇索引(clustered indexes)的形式提供數據的物理鏈接。不過(guò),這種鏈接是應用于各個(gè)表格而不是整體層次上的。)
令人遺憾的是這種可伸縮性是有限的。就像層次型數據庫,原生XML數據庫中所用的物理連接只能作用于特定的層次。也就是說(shuō),如果數據的讀取和數據的存儲在同一層次下,則讀取速度很快,否則就不一定快。例如將客戶(hù)信息存儲在各個(gè)銷(xiāo)售訂單文件中,則讀取銷(xiāo)售訂單時(shí)的速度很快,而如果需要的數據視圖不同,比如要找出某個(gè)客戶(hù)的所有訂單將會(huì )很慢,因為此時(shí)物理連接已不再適用。)
為了緩解這個(gè)問(wèn)題,原生XML數據庫大量使用了索引,經(jīng)常對所有元素和屬性都作了索引。這雖然有助于減少讀取時(shí)間,卻增加了更新時(shí)間,因為維護這種索引的代價(jià)很高。在只讀的環(huán)境下這無(wú)關(guān)緊要,在交易頻繁的環(huán)境下可能造成麻煩。
最后,對于未索引數據的查找來(lái)說(shuō),原生XML數據庫的可伸縮性比關(guān)系型數據庫差的多。此時(shí)這兩種數據庫都要線(xiàn)性地查找數據,而原生XML數據庫的情況更為糟糕,因為它的數據不是完全規范的。比如你要查找某個(gè)日期的所有銷(xiāo)售訂單,而日期是未經(jīng)索引的。如果用的是關(guān)系型數據庫,就要讀取所有OrderDate字段的值,而對于原生XML數據庫,這意味著(zhù)要讀取每個(gè)銷(xiāo)售訂單文件,并從中查找<OrderDate>元素。不但需要讀取<OrderDate>元素的內容;而且還要讀取所有其它文件的內容。對于基于文本的原生XML數據庫,情況也很不妙:在與目標日期比較之前,必須先對文本進(jìn)行解析并轉換為日期格式。
那么對你來(lái)說(shuō),可伸縮性是否嚴重?這完全取決于你的應用。如果你的應用程序中所需的數據一般都和其存儲形式相同,則原生XML數據庫的可伸縮性應是不錯的。許多以文本為中心的應用就屬于這種情形。例如組成產(chǎn)品手冊的文檔幾乎總是作為整體讀取的。反之,如果你的應用中數據視圖不是很確定,則可伸縮性有可能出問(wèn)題。
對于原生XML數據庫的討論就到此結束。在接下來(lái)的兩部分中,我們將考察兩種特殊的原生XML數據庫:可持久化DOM和內容管理系統。
6.3 可持久化DOM (Persistent DOMs, PDOMs)
可持久化DOM(persistent DOM)或PDOM是在某種持久性存儲[介質(zhì)]上實(shí)現了DOM 的一種特殊的原生XML數據庫。與大多數以DOM樹(shù)返回文檔的原生XML數據庫不同,PDOM返回的DOM是實(shí)時(shí)的(live)。也就是說(shuō),對DOM所作的改變直接反映在數據庫中。(這種改變實(shí)際上是否馬上做出或者通過(guò)調用一個(gè)方法來(lái)實(shí)現取決于數據庫)大多數原生XML數據庫返回個(gè)應用程序的DOM樹(shù)是一個(gè)復制品,而數據庫中的改變是通過(guò)XML更新語(yǔ)言,或者是通過(guò)替換整個(gè)文件來(lái)實(shí)現的。
由于PDOM樹(shù)是實(shí)時(shí)的,數據庫通常是在本地。這就是說(shuō),它和應用程序在同一個(gè)進(jìn)程空間,或者至少在同一部機器(盡管這并不是必需的)。這是出于性能上的考慮,因為外部數據庫上的PDOM必須經(jīng)常向遠程服務(wù)器發(fā)出請求。
PDOM在DOM應用程序中所起的作用和在面向對象的應用程序中面向對象的數據庫的作用一樣:它為應用程序的數據提供了可持久化的存儲,也可作為應用程序的虛擬內存。后一種作用對于操作大型文件的DOM應用來(lái)說(shuō)有著(zhù)特殊的重要性,因為DOM與XML文件長(cháng)度之比很容易超過(guò)10。(實(shí)際的系數取決于文件中文本的平均長(cháng)度,文本的平均長(cháng)度較小的文件其系數較高。)
6.4 內容管理系統 (Content Management Systems)
內容管理系統是原生XML數據庫的另一種特殊形式。它們是為管理手工寫(xiě)成的文件例如用戶(hù)手冊和技術(shù)草稿(white paper)而專(zhuān)門(mén)設計的,并且建立在原生XML數據庫之上。這個(gè)數據庫一般是處于用戶(hù)看不到的后臺,而提供給用戶(hù)的功能有:
版本和訪(fǎng)問(wèn)控制。
搜索引擎。
XML/SGML編輯器。
發(fā)布引擎。比如以書(shū)面、CD形式或在Web上發(fā)布。
內容與樣式的分離。
可通過(guò)腳本或編程擴展。
數據庫數據的集成(integration)。
相對于文件管理系統,內容管理系統這個(gè)術(shù)語(yǔ)道出了這樣的事實(shí):它使你可以將文件分為離散的片斷(比如示例、過(guò)程、章節或旁注)和元數據(例如作者、修訂日期、文件編號),而不是以整體管理文件。這不但簡(jiǎn)化了一個(gè)文件多個(gè)作者時(shí)的協(xié)調工作,而且能使你從現有文件部分組合成全新的文件。
7.0 XML 數據庫產(chǎn)品 (Database Products)
關(guān)于最新的XML數據庫產(chǎn)品,參見(jiàn)XML Database Products.
8.0 相關(guān)鏈接 (Additional Links)
有關(guān)XML/數據庫的相關(guān)資源,包括軟件和文章,參見(jiàn)XML / Database Links。
9.0 意見(jiàn)和反饋 (Comments and Feedback)
請將意見(jiàn)和反饋發(fā)送給Ronald Bourret rpbourret@rpbourret.com。我經(jīng)常外出旅行,有可能延誤兩到三個(gè)星期。
感謝Michael Champion, John Cowan, Marc Cyrenne, Marc de Graauw, Kelvin Ginn, Ingo Macherius, Lars Martin, Nick Leaton, Evan Lenz, Michael Rys, Walter Perry, Kimbro Staken, Jim Tivy, Phillipe Vauclair, Dylan Walsh, Irsan Widarto, Morten Primdahl 及其他人的意見(jiàn)和耐心。
聯(lián)系客服