簡介
PHP 支援簡單的 Web 應用程式開發和部署環境。這是它得到普遍應用的原因之一。DB2 9的原生 XML 功能進一步簡化了開發過程。這種簡化體現在以下方面:
- 應用程式代碼較少,複雜性降低
- 較簡單的關係模式
- 更好地管理因為更改業務需要而發生的模式演化
|
在本文中,我們將在該基礎上進行構建並說明使用 DB2 原生 XML 功能簡化應用程式代碼和關係模式的有效性。還將講述業務需求更改對資料的影響(模式演化)以及對應用程式代碼和關係模式的影響。
為了說明我們的推理,將通過一個類比線上商店的使用情景來進行說明,該商店向註冊客戶出售古董銀器。
我們將在該情景中說明的一些要點包括:
| 設定 PHP 環境的容易程度將 DB2 原生 XML 功能與 PHP 應用程式(包括用 PHP 和 XQuery 編寫的 Web 服務)整合的容易程度使用 XQuery、預存程序和視圖將商務邏輯和資料轉換放到資料庫中。 |
在該情景中使用的 DB2 XML 功能將包含以下方面:
| 按分列結構在列中儲存 XML 文檔使用 XQuery 進行搜尋和發布在 DB2 預存程序和視圖中支援 XML使用 XML 索引提高效能 |
為突出使用 DB2 原生 XML 支援對 PHP 應用程式代碼和關係模式設計的影響,該情景將建立一個並行環境,該環境使用不包含任何 XML 功能的資料庫(例如,MySQL)。我們將研究這兩個環境在應用程式代碼、資料庫查詢和關係模式方面的差異。還將說明選擇特定代碼、模式或查詢以及備選方案(如果可能)的理由。
情景
該情景類比向註冊客戶出售古董銀器的線上商店。因為該情景的一個目的是說明不同的資料庫環境以及它們對應用程式代碼的影響,所以我們將對兩個應用程式進行同時說明,一個應用程式使用 DB2 原生 XML,另一個應用程式使用類似 MySQL 的開放源碼 RDMS,具有有限的 XML 功能或沒有任何 XML 功能。
因此,訪問 Web 網站的客戶將看到一個包含兩個垂直面板的頁面。每個面板都將顯示同一應用程式的一個版本,提供相同的使用者體驗,但在後端使用不同的資料庫:
| 具有原生 XML 支援的 DB2其他 RDBMS(在本例中為不使用任何 XML 功能的 DB2) |
為顯示應用程式代碼的差異,每個面板進一步分為兩個水平架構,上面的架構顯示線上商店,下面部分顯示程式碼片段。當使用者進行任何操作(如單擊某一種類或產品映像)時,上面部分都會產生一個新頁面。下面部分顯示建立此頁面所需的代碼。
圖 1. 應用程式範例面板
498)this.width=498;' onmousewheel = 'javascript:return big(this)' height=355 alt=應用程式範例面板 src="/files/uploadimg/20060809/1134560.jpg" width=572>
這將說明,雖然在任何一個應用程式中使用者的體驗沒有變化,但代碼複雜性發生了很大變化。這種對比將突出用 PHP 編寫的普通 SMB 應用程式使用 DB2 原生 XML 功能的好處。
注意:我們對此情景的假設是業務資料已經是 XML 格式的,儘管資料庫可能沒有任何 XML 功能。這將產生可用於資料庫的使用 XML 功能的 PHP 應用程式代碼(如簡單 DOM)。具有有限 XML 功能或無 XML 功能的資料庫將 XML 資料存放區為 CLOB/BLOB 資料類型,或分割到關係欄位中。
在 Web 網站中瀏覽時的功能和使用者體驗
Web 網站將為使用者提供索引,列出商店中所有可用銀器的種類和品牌。使用者單擊某一種類或品牌時,將顯示該種類或品牌的貨品列表。挑選清單中的任何貨品都會在頁面中顯示該貨品的詳細資料。使用者可以將這些貨品添加到購物車中。一旦使用者提交了訂單,將會建立採購訂單並根據此採購訂單向使用者提供發票。使用者可以隨時檢查購物車中的貨品。使用者還能夠得到他們過去已訂購的所有貨品的報告。
應用程式體繫結構
圖 2 顯示了應用程式範例的基本體繫結構。
圖 2. 應用程式體繫結構
498)this.width=498;' onmousewheel = 'javascript:return big(this)' height=431 alt=應用程式體繫結構 src="/files/uploadimg/20060809/1134561.gif" width=473>
關係和 XML 模式
XML 文檔和模式
原生 XML 儲存不需要 XML 列與特定 XML 模式關聯。需要對插入到資料庫中的 XML 文檔進行的任何驗證都在插入語句中使用 SQL/XML 函數顯式地進行。附錄中包含 XML 文檔樣本。
關係模式
對於這兩個資料庫,用於儲存這些 XML 文檔的關係模式將有所不同。
對於 DB2 原生 XML,將有三個表,每個表包含兩列。
圖 3. DB2 原生 XML 模式
498)this.width=498;' onmousewheel = 'javascript:return big(this)' height=72 alt="原生 XML 情景的關係模式" src="/files/uploadimg/20060809/1134562.gif" width=460>
對於無 XML 支援的 RDBMS,將有四個表,每個表包含多個列:
圖 4. 無 XML 支援的情景的關係模式
498)this.width=498;' onmousewheel = 'javascript:return big(this)' height=261 alt="無 XML 支援的情景的關係模式" src="/files/uploadimg/20060809/1134563.jpg" width=563>
可以看出,與無 XML 支援的 RDBMS 相比,DB2 原生 XML 的關係模式非常簡單。
我們已經通過將採購訂單文檔儲存為 BLOB,在基本關聯式資料庫中盡量保持採購訂單表模式簡單。當查看產生訂單記錄時,這種操作的作用將非常明顯。
DB2 PHP 驅動程式
在開始講述 PHP 應用程式代碼之前,我們先瞭解一下 PHP 的 DB2 驅動程式。ibm_db2 驅動程式支援兩種串連資料庫的方法:編目 和非編目。編目串連可以是本機資料庫(如果有 DB2 伺服器在本地運行),也可以是遠程 DB2 伺服器節點。第二種方法通常用於遠程非編目串連,需要構建連接字串(類似於 JDBC URL)以建立非編目串連。以下代碼串連編目資料庫。(客戶機應用程式不需要知道或關注編目串連時本地的還是遠端。)
$conn = db2_connect($dbname, $dbuser, $dbpass); if(!$conn) { echo db2_conn_errormsg(); die("Unable to connect to database!"); } |
還可以使用 db2_pconnect 建立與資料庫的持久串連。調用 db2_close 時,持久串連實際將不被關閉,因為串連控制代碼將在請求中保留。有關 PHP 的 IBM DB2 驅動程式的詳細資料,請訪問 http://www.php.net/manual/en/ref.ibm-db2.php。在下面的程式碼片段中,假設 $conn 是有效串連控制代碼。
填充資料庫
在 Web 網站可以開通之前,需要使用客戶資訊和產品目錄填充資料庫。對於我們的情景,將不詳細說明如何擷取此資料。假設其以 XML 文檔的形式包含在本地檔案系統的檔案中。下面顯示了串連資料庫和執行 SQL 插入語句所需的 PHP 程式碼片段樣本。
DB2 Viper
因為每個產品文檔都包含產品識別碼 屬性,我們需要使用 PHP 的 SimpleXml API 提取該 ID。
注意: 使用此 API 比操作 DOM 對象容易得多,該對象在 PHP 版本 5 之前是惟一選擇。
- 建立資料庫連接:
$conn =db2_connect($dbname, $dbuser, $dbpass); |
- 從檔案開啟文檔,成為一個變數:
$fileContents = file_get_contents("products/p1.xml"); |
- 從此變數建立簡單的 XML 對象:
$dom = simplexml_load_string($fileContents); |
- 從文檔中提取產品識別碼:
$prodID = (string) $dom["pid"]; |
- 建立準備好的語句,將 XML 文檔插入資料庫中:
$stmt =db2_prepare($conn, "INSERT INTO xmlproduct VALUES (?, ?)"); |
- 將從文檔中提取的產品識別碼 作為參數與文檔一起傳遞到查詢:
db2_execute($stmt, array($prodID, $fileContents); |
注意插入資料到 XML 列中與插入資料到任何 CLOB 列中沒有區別。因為這個 DB2 新版本允許在插入時對 XML 資料進行隱式分析,我們不需要對傳入值顯式地調用 XMLPARSE。如果我們希望在 XML 標記周圍保留無關空格,則可以使用帶 RESERVE WHITESPACE 選項的 XMLPARSE 函數。
注意: 這些程式碼片段中的查詢都使用斜體表示,以區別於 PHP 應用程式代碼。
非 XML RDBMS
因為此資料庫不具有任何 XML 功能,產品文檔需要分解到兩個關係表中。關係模式和 XML 模式之間的映射資訊將直接嵌入 PHP 應用程式代碼中。
- 首先載入文檔到 DOM 中:
$fileContents = file_get_contents("$products/p1.xml"); $dom = simplexml_load_string($fileContents); |
- 現在將產品的單個元素分割到本地變數中:
$prodID = (string) $dom["pid"]; $prodName = (string) $dom->description->name; $prodDetails = (string) $dom->description->details; $prodPrice = (float) $dom->description->price; |
- 每個產品的映像 URL 需要儲存在單獨的映像表中:
$images = array(); foreach($dom->description->images->image as $image) { switch((string) $image[type']) { case thumbnail':$prodImgThumb = (string) $image; $prodImgAlias = (string) $image[alias']; if(!$prodImgAlias) $prodImgAlias = NULL; $stmt = db2_prepare($conn, "INSERT INTO sqlimages (Pid, Type, Alias, Location) VALUES (?, ?, ?, ?)"); db2_execute($stmt, array($prodID, thumbnail', $prodImgAlias, $prodImgThumb)); case full': $prodImgFull = (string) $image; $prodImgAlias = (string) $image[alias']; if(!$prodImgAlias) $prodImgAlias = NULL; $stmt = db2_prepare($conn, "INSERT INTO sqlimages (Pid, Type, Alias, Location) VALUES (?, ?, ?, ?)"); db2_execute($stmt, array($prodID, full', $prodImgAlias, $prodImgFull)); } } |
- 當前實現 ibm_db2 驅動程式不能適當地將 NULL 變數作為參數來處理,以便執行函數;因此我們使用一個非強制性解決方案:
if(!$prodBrand) $prodBrand = " "; if(!$prodCategory) $prodCategory = " "; if(!$prodImgFull) $prodImgFull = " "; |
- 現在儲存產品表中的產品資訊:
$stmt = db2_prepare($conn, "INSERT INTO sqlproduct (Pid, Name, Details, Brand, Category, Price, Weight, Size, Description) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); db2_execute($stmt, array($prodID, $prodName, $prodDetails, $prodBrand, $prodCategory, $prodPrice, $prodWeight, $prodSize, $fileContents)); |
建立首頁
首頁包含線上商店中所有可用產品的種類和品牌的索引。索引的右邊地區顯示所有貨品的列表。
圖 5. 首頁
498)this.width=498;' onmousewheel = 'javascript:return big(this)' height=451 alt=首頁 src="/files/uploadimg/20060809/1134564.jpg" width=438>
建立種類和品牌的索引列表
索引通過查詢資料庫中所有產品的惟一種類和品牌的列表而建立。啟動應用程式時將建立此列表。
DB2 Viper
- 首先建立 DB2 視圖,以使用 XQuery 列出種類,XQuery 在所有產品中迴圈並返回所有惟一種類:
CREATE VIEW Categories(Category) AS SELECT DISTINCT(XMLCAST( XMLQUERY(for $i in $t/product/description/category return $i' PASSING BY REF T.DESCRIPTION AS "t" RETURNING SEQUENCE) AS VARCHAR(128))) FROM xmlproduct AS t |
- 現在從應用程式調用該視圖:
$stmt = db2_exec($conn, "SELECT * FROM Categories"); while(list($cat) = db2_fetch_array($stmt)) { echo " ";} |
這兩種情況中的應用程式代碼相似。建立 XML 資料檢視使我們可以輕鬆地查詢檢視,從而有助於從應用程式代碼理解產品 XML 的結構。需要更改視圖中的 XQuery 以尋找品牌要素,同樣 SQL 調用也需要查看 Brand 列。
模式演化對索引列表的影響
根據客戶回函,我們需要允許使用者瀏覽網站,以尋找鍍銀的貨品或由純銀製造的貨品。我們看一下向索引中添加子種類對以下各項的影響:XML 模式、關係模式、查詢和 PHP 應用程式代碼。
對 XML 模式和文檔執行個體的影響
向產品 XML 模式中的種類元素添加新屬性(catx)。產品的所有新 XML 文檔現在都用純銀或鍍銀適當地填充了此屬性:
Miscellaneous
對關係模式的影響
- DB2 Viper
這將不需要對關係模式進行任何更改,因為 XML 文檔儲存在單個列中。
- 非 XML RDBMS
在基本關聯式資料庫中,將需要更改產品表的模式,添加名為 catx 的另一列。這可能涉及刪除並重新插入所有產品文檔。
對查詢的影響
- DB2 Viper 建立索引所需的 XQuery 將發生變化以在條件中包含這個新屬性。同樣,用於根據索引中的選擇列出貨品 XQuery 也將發生變化來包括新條件。
- 非 XML RDBMS
插入語句將發生變化以包括新列。
建立索引所需的查詢將發生變化以在 WHERE 子句中包括這個新列。同樣,用於根據索引中的選擇列出貨品的查詢也將發生變化以包括新條件。
對應用程式代碼的影響
- DB2 Viper
應用程式代碼將沒有任何更改。
- 非 XML RDBMS
- 將需要額外的 DOM 代碼,以分割出子種類資訊。
- INSERT 語句將需要額外的參數。
- 所有資料都有可能需要重新插入,這導致終端使用者有一段時間無法操作。
使用者單擊種類或品牌時列出貨品
使用者單擊特定種類或品牌時,將產生該種類或品牌中所有貨品的列表。列表中的每個貨品都有簡短描述和到縮圖像的 URL。此列表顯示在首頁中並在其中進行格式設定。
圖 6. 某一種類中的貨品列表
498)this.width=498;' onmousewheel = 'javascript:return big(this)' height=356 alt=某一種類中的貨品列表 src="/files/uploadimg/20060809/1134565.jpg" width=572>
DB2 Viper
在 DB2 中,XQuery 不僅建立列表,而且還將其轉換為 HTML 輸出,從而瀏覽器可以直接使用。使用 XQuery 的此功能,不僅可以推出商務邏輯,而且發行就緒到資料庫伺服器,從而有效地使中介層應用程式非常簡單。這正是使用 PHP 而不使用 Java™ 或 VS .NET® 的原因。
$xquery =for $i in $t/product let $thumb := $i/description/images/image[@type="thumbnail"] where $i/description/category = " . htmlentities($category) . " return
http://www.bkjia.com/PHPjc/446840.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/446840.htmlTechArticle簡介 PHP 支援簡單的 Web 應用程式開發和部署環境。這是它得到普遍應用的原因之一。DB2 9的原生 XML 功能進一步簡化了開發過程。這種簡化... -
|