程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> DB2數據庫 >> DB2教程 >> 利用DB2 9原生XML和PHP來簡化XML應用程序

利用DB2 9原生XML和PHP來簡化XML應用程序

編輯:DB2教程

簡介

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. 示例應用程序面板

    示例應用程序面板

    這將說明,雖然在任何一個應用程序中用戶的體驗沒有變化,但代碼復雜性發生了很大變化。這種對比將突出用 PHP 編寫的普通 SMB 應用程序使用 DB2 原生 XML 功能的好處。

    注意:我們對此情景的假設是業務數據已經是 XML 格式的,盡管數據庫可能沒有任何 XML 功能。這將產生可用於數據庫的使用 XML 功能的 PHP 應用程序代碼(如簡單 DOM)。具有有限 XML 功能或無 XML 功能的數據庫將 XML 數據存儲為 CLOB/BLOB 數據類型,或分割到關系字段中。

    在 Web 站點中浏覽時的功能和用戶體驗

    Web 站點將為用戶提供索引,列出商店中所有可用銀器的種類和品牌。用戶單擊某一種類或品牌時,將顯示該種類或品牌的貨品列表。選擇列表中的任何貨品都會在頁面中顯示該貨品的詳細信息。用戶可以將這些貨品添加到購物車中。一旦用戶提交了訂單,將會創建采購訂單並根據此采購訂單向用戶提供發票。用戶可以隨時檢查購物車中的貨品。用戶還能夠得到他們過去已訂購的所有貨品的報告。

    應用程序體系結構

    圖 2 顯示了示例應用程序的基本體系結構。

    圖 2. 應用程序體系結構

    應用程序體系結構

    關系和 XML 模式

    XML 文檔和模式

    原生 XML 存儲不需要 XML 列與特定 XML 模式關聯。需要對插入到數據庫中的 XML 文檔進行的任何驗證都在插入語句中使用 SQL/XML 函數顯式地進行。附錄中包含 XML 文檔示例。

  • 每個產品的圖像 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. 主頁

      主頁

      創建種類和品牌的索引列表

      索引通過查詢數據庫中所有產品的惟一種類和品牌的列表而創建。啟動應用程序時將創建此列表。

      DB2 Viper
      1. 首先創建 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

      2. 現在從應用程序調用該視圖:

        $stmt = db2_exec($conn, "SELECT * FROM CategorIEs");

        while(list($cat) = db2_fetch_array($stmt)) {

        echo "$cat

        "; }

      非 XML RDBMS

      從產品表創建種類的惟一列表:

      $stmt = db2_exec($conn, "SELECT DISTINCT(category) FROM SQLPRODUCT");

      while(list($cat) = db2_fetch_array($stmt)) {

      echo "$cat

      ";}

      這兩種情況中的應用程序代碼相似。創建 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. 某一種類中的貨品列表

          某一種類中的貨品列表

          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









          {$i/description/name}



          ;

          $stmt = db2_prepare($conn, "SELECT XMLSERIALIZE(XMLQUERY(

          $xquery' PASSING BY REF T.DESCRIPTION AS \"t\"

          RETURNING SEQUENCE) AS CLOB(32K)) FROM XMLproduct AS t");

          db2_execute($stmt);

          while(list($product) = db2_fetch_array($stmt)){echo $product;}

          查看上面的應用程序代碼,我們注意到 PHP 代碼減少為兩行,而數據庫查詢包含大部分邏輯。

          注意: 我們需要對使用 Html 實體的任何傳入 CGI 變量(如種類)進行轉義,從而它們在插入 XQuery 時不包含任何非法的非轉義實體。

          雖然 XQuery 可以進行發布轉換,但在許多情況下可能不適合進行此操作。由於設計、性能和樣式原因,可能更適合於在中間層或客戶機中使用 XSLT 轉換來創建最終的 Web 頁。在許多情況中,將兩個查詢捆綁為一個查詢會更方便。使用 XQuery 並不阻止開發人員使用 XSLT 進行轉換。我們在此的嘗試將顯示 XQuery 不僅可以進行數據搜索,而且可以對數據運行復雜業務邏輯和轉換。

          非 XML RDBMS

          首先查詢數據庫以獲取與所選種類匹配的所有貨品的行集:


          $sql = "SELECT P.Pid, P.Name, I.Location FROM sqlproduct P, sqlimages I

          WHERE P.Category = ? AND I.Pid = P.Pid AND I.Type = ?");

          $stmt = db2_prepare($conn, $sql);

          db2_execute($stmt, array($category, "thumbnail"));

          然後在結果集中循環並使用 PHP 代碼創建 Web 頁:

          while(list($prodPid, $prodName, $prodImg) = db2_fetch_array($stmt)) {

          ?>














          }

          ?>

          雖然發布代碼與 XQuery 中的非常相似,一個顯著區別就是此代碼在中間層中運行和維護,而不是在數據庫服務器中。所以如果 XQuery 在數據庫服務器中注冊為存儲過程,其維護將作為數據庫的一部分。我們將在下一步中進行此操作。

          產品詳細信息

          用戶單擊商店列出的任何產品時,應用程序都會創建一個詳細產品頁面,其中包含該產品的說明、尺寸、價格和可能的附加圖像等信息。

          圖 7. 產品詳細信息

          產品詳細信息

          DB2 Viper

          創建產品詳細信息的 XQuery 保存為存儲過程。

          用於創建產品詳細信息的存儲過程

          用 SQL/PL 編寫 getProduct 存儲過程,其接受產品 ID 作為參數,並返回記錄集的游標。這個存儲過程主要執行 XQuery,其在頁面一側生成顯示產品詳細信息及其圖片以及其他縮略圖的版面。

          CREATE PROCEDURE getProduct(IN id VARCHAR(10))

          DYNAMIC RESULT SETS 1

          LANGUAGE SQL

          BEGIN

          BEGIN

          DECLARE c_cur CURSOR WITH RETURN FOR

          SELECT XMLSERIALIZE(XMLQUERY(for $i in $t/product

          let $thumb := $i/description/images/image[@type="thumbnail"]

          let $name := $i/description/name/text()

          let $details := $i/description/details/text()

          let $price := $i/description/price

          let $size := $i/description/size

          return



          {$name}



          { for $j in $i/description/images/image[@type != "thumbnail"][1] return




          src="data/images/{$thumb}.jpg"

          width="200"/>



          }



          Details: {$details}

          Price: ${$price/text()}

          Size: {$size/text()} {$size/@units/text()}


          >Click here to Buy





          { for $j in $i/description/images/image[@type != "thumbnail"]

          [position() != 1] return




          onMouSEOut="document.mainPic.src=

          data/images/{$i/description/images/image[@type !=

          "thumbnail"][1]}.jpg''">







          }





          PASSING T.DESCRIPTION AS "t" RETURNING

          SEQUENCE) AS CLOB(32K))

          FROM XMLproduct T WHERE Pid = id;

          OPEN c_cur;

          END;

          END

          注意: XQuery 中的與號需要進行轉義。這適用於所有特殊字符。

          重點: 因為 XQuery 處理 XML 類型,所以所有返回的數據都將對特殊字符進行轉義。解決此問題的一種方法是使用轉型函數將查詢的返回數據轉型為 VARCHAR。

          應用程序代碼

          $stmt = db2_prepare($conn, "CALL getProduct(?)");

          db2_execute($stmt, array($pid));

          list($product) = db2_fetch_array($stmt);

          echo $product;

          應用程序代碼現在簡化為對存儲過程和將結果輸出到浏覽器的任務的簡單調用。現在大多數應用程序代碼都在數據庫服務器中維護和運行。發現的另一個事實是,從存儲過程查詢數據比直接從代碼執行查詢簡單,至少與其一樣簡單。

          非 XML RDBMS

          雖然可以在關系情況下創建存儲過程,但對於這種情況可能會復雜得多。
          1. 從產品表獲取產品詳細信息:



            $stmt = db2_prepare($conn, "SELECT P.Name, P.Details, P.Price,

            P.Size, I.Location, I.Alias FROM

            sqlproduct P, sqlimages I WHERE P.Pid = ? AND

            P.Pid = I.Pid AND I.Type = ? FETCH FIRST

            ROW ONLY");

            db2_execute($stmt, array($pid, full'));

            list($prodName, $prodDetails, $prodPrice, $prodSize, $prodImgThumb,

            $prodImgAlias) = db2_fetch_array($stmt);

          2. 現在通過在數據周圍放置 Html 標記創建顯示:













            通過使用 構造,可以在這裡混合 PHP 和 Html 代碼:



            Details:

            Price: $

            Size:

            Click here to Buy





          3. 查詢與此產品關聯的圖像並將其 URL 添加到輸出 Web 頁中:




            $stmt = db2_prepare($conn, "SELECT DISTINCT(Location)

            FROM sqlimages WHERE Pid = ?

            AND Type = ? AND NOT Location = ?");

            db2_execute($stmt, array($pid, full', $prodImgThumb));

            while(list($prodImg) = db2_fetch_array($stmt)) {

            ?>








            }

            ?>





          因為產品數據已經分割到兩個表中,且 PHP 和 Html 代碼已經混合,我們需要進行兩個單獨查詢來獲取產品詳細信息和圖像位置。

          購物車

          購物車是任何在線商店不可缺少的一部分。因此,它是一個適合創建為 Web 服務的實用程序。可定制此 Web 服務來計算價格、稅款、幣種換算、運輸成本等等。在我們的實現示例中,已經使用 PHP 和 XQuery 創建了 Web 服務,可以進行價格和稅款計算。

          客戶添加到購物車中的貨品保存為客戶端 cookie。此 cookIE 在 PHP 中以關聯數組形式讀入並指定給變量 $cart。

          圖 8. 購物車

          購物車

          DB2 Viper

          Web 服務提供商和查詢
          1. 同樣,我們已經使用 XQuery 將輸出版面和業務邏輯嵌入到一個查詢中。除了購物車信息,Web 服務還接受銷售稅率參數,購物車信息為一個包含產品 ID 及各自數量的 XML 文檔。這使我們可以將購物車信息作為 XML 值傳遞到 XQuery 中。




            function getCart($cart, $taxrate) {

            global $conn;

            $result = "";

            $xquery =

            for $dummy in (1)

          2. 在 XQuery 中,與其他任何原生 XML 文檔一樣,變量 $cart 可以進行迭代:



            let $items := for $i in $cart/items/item

            let $product := db2-fn:xmlcolumn("XMLPRODUCT.DESCRIPTION")

            /product[@pid =

            $i/@pid]/description

            let $name := $product/name/text()

            let $price := $product/price/text()

            let $itemPrice := if($price = 0 or empty($price)) then ("$0.00")

            else (concat("$", $price))

            return





          3. 對於每個貨品,使用從購物車信息傳遞的數量和從數據庫中的產品目錄信息獲取的價格,計算該貨品的總價:



            {$price * $i/@quantity}



            {$name}





            {xs:integer($i/@quantity)}

            Remove





            {$itemPrice}





            return



          4. 返回 XML(XHtml)結構,包含每個貨品的總價計算以及發布信息:



            {$items}





            Subtotal





          5. 從返回的結構計算購物車中所有貨品的總價。我們實際上將查詢的一部分的輸出作為該查詢的另一部分的輸入變量。



            Total all

            ${ sum( $items/noframes/text() ) }









            Tax

            ({$tax * 100}%)




          6. 使用從客戶機傳遞到 Web 服務的稅變量計算付款。

            注意: 上面計算的所有貨品的總價可以使用 let 語句分配給一個變量。然後此變量可以用於計算稅和總付款。

            ${ xs:decimal(sum($items/noframes/text()))

            * $tax }










            Grand Total<

            /strong>




            ${ xs:decimal(sum($items/noframes/text())) * (1 + $tax) } <

            /strong>



            =

            =;

            我們留給讀者一個練習,以更好的形式重寫循環的最外層。
          7. 雖然 XQuery 不支持運行時參數綁定,但是有一個解決方案。運行時參數可通過使用 XMLQuery 函數的 PASSING BY 子句傳遞到 XQuery 中:



            $stmt = db2_prepare($conn, "VALUES( XMLSERIALIZE(

            XMLQUERY($xquery' PASSING BY

            REF CAST(? AS XML) AS \"cart\" , CAST(? AS DECIMAL

            (10,8)) AS \"tax\" RETURNING

            SEQUENCE) AS CLOB(32K)))");

            注意,購物車信息以 XML 字符串的形式傳遞到查詢中。此字符串通過使用 CAST (? As XML) 函數轉換為 XML 類型。
          8. 如果查詢注冊為存儲過程,則運行此 Web 服務所需的 PHP 代碼將簡化為以下幾行:



            if($stmt) {

            if(!db2_execute($stmt, array($cart, $taxrate))) {

            return db2_stmt_errormsg($stmt);

            }

            list($result) = db2_fetch_array($stmt);

            if(!$result) return db2_stmt_errormsg($stmt);

            } else {

            $result = db2_stmt_errormsg();

            }return $result;

            }

          9. 注冊 Web 服務:



            $server = new SoapServer(null, array(uri' =

            > http://ibm.com/db2/XML/PHP'));

            $server->addFunction(getCart');

            $server->handle(); ?>

          正如可以從以上代碼示例中看到的,使用 PHP 和 DB2 原生 XML 支持創建 Web 服務非常簡單。而且,由於服務簡單,我們不需要定義 WSDL(Web Services Description Language,Web 服務描述語言)文檔。

          Web 服務客戶機

          現在可以從客戶機代碼調用此 Web 服務,在 Web 站點中顯示購物車信息。實際購物車頁面就是一個調用 Web 服務的客戶機。
          1. 創建購物車信息的 XML 字符串,它將作為參數傳遞到 Web 服務:




            $cartXML = "";

            foreach($cart as $cpid => $quantity) {

            $cartXML .= "";

            }

            $cartXML .= "
            ";

            $client = new SoapClIEnt(null, array(location' =>

            http://127.0.0.1/cartsvc.PHP',

            uri' => http://ibm.com/db2/XML/PHP'));

            $taxrate = 0.0;

          2. 調用 Web 服務並將返回的字符串輸出到浏覽器:



            echo $clIEnt->getCart($cartXML, $taxrate); ?>

              注意: 因為購物車作為 Web 服務來實現,所以可以從任何語言調用它。

              非 XML RDBMS

              此示例的關系版本沒有 Web 服務或銷售稅計算。雖然查詢看起來比 XQuery 簡單,但我們必須為購物車中的每個貨品查詢數據庫,導致數據庫流量增加,應用程序代碼有些更面向循環。由於可以使用 PHP 容易地創建 Web 服務,從關系部分創建 Web 服務將不會很難。與在 XML 版本中一樣,getCart 函數會接受購物車作為參數,其格式需要提前確定。如果是 XML 值,則需要使用 DOM 來讀取購物車,或者可以是關聯數組,只需對以上代碼進行很少的更改。另一方面,如果希望創建使用關系數據庫顯示購物車的存儲過程,需要將 Html 內容與從數據庫中檢索的數據合並。將需要大量工作以使表示代碼不在存儲過程中,而在應用程序中。


              foreach($cart as $pid => $quantity) {

              $stmt = db2_prepare($conn, "SELECT Name, Price FROM sqlproduct WHERE Pid = ?");

              db2_execute($stmt, array($pid));

              if($stmt) {

              list($prodName, $prodPrice) = db2_fetch_array($stmt);

              ?>













              Remove





              $






              }

              }

              ?>

              采購訂單

              一旦用戶選擇付帳,購物車將發送到應用程序,並為采購的貨品生成 XML 采購訂單文檔。

              用於創建采購訂單的 XML 代碼和關系代碼大部分都相同,惟一的差別是用於查找產品當前價格的查詢。

              $stmt = db2_prepare($conn, "VALUES (NEXT VALUE FOR POid)");

              db2_execute($stmt);

              list($POid) = db2_fetch_array($stmt);

              foreach($cart as $pid => $quantity) {

              $xquery = $t/product/description/price/text()';

              $stmt = db2_prepare($conn, "SELECT XMLSERIALIZE(XMLQUERY($xquery' PASSING BY REF

              T.DESCRIPTION AS \"t\" RETURNING SEQUENCE) AS VARCHAR(8)) FROM XMLproduct

              AS t WHERE Pid = ?");

              db2_execute($stmt, array($pid));

              list($price) = db2_fetch_array($stmt);

              雖然我們可以使用 DOM 創建采購訂單,在本例中合並 XML 片段將更簡單。

              $PO .= " \n";

              }



              $stmt = db2_prepare($conn, "INSERT INTO XMLporder (POid, POrder) VALUES (?, ?)");

              db2_execute($stmt, array($POid, $PO));

              采購訂單(PO)在關系數據庫中存儲為 CLOB(而不分割)。完整存儲的好處是任何由於采購訂單的變化(如運輸等其他信息)而發生的模式演化都不會有什麼影響。將 PO 存儲為 CLOB,則可以在應用程序代碼中使用 DOM 來檢索相關信息。但是,關系存儲的簡單和模式演化的好處會被查詢性能的降低所抵消,當我們嘗試創建采購歷史記錄報告時會發現這一點。

              發票

              發票在付帳時返回給客戶。該發票是通過查詢剛剛創建的采購訂單而生成的。因為采購訂單不包含詳細產品信息,所以需要進行單獨查詢,以便從產品表中查找產品詳細信息。

              圖 9. 發票

              發票

              DB2 Viper
              1. 同樣,我們使用單個 XQuery 創建最終發票。

                $xquery =

                for $po in $t/purchaSEOrder

                let $sum := for $item in $po/items/item return $item/@quantity * $item/@price

                let $items := for $item in $po/items/item

              2. 在采購訂單和產品表之間創建聯接以獲取產品詳細信息。



                let $name := for $i in db2-fn:xmlcolumn("XMLPRODUCT.DESCRIPTION")/product where

                $i/@pid = $item/@pid return $i/description/name/text()

                return





                {$name}





                {xs:string($item/@quantity)}





                ${xs:string($item/@price)}





                return



                {$items}

                {$po/text()}





                Total

                ${sum($sum)}





                ;

              有趣的是,以上 XQuery 與用於顯示購物車內容的 XQuery 相似:

              $stmt = db2_prepare($conn, "SELECT XMLSERIALIZE(XMLQUERY($xquery' PASSING BY REF

              T.PORDER AS \"t\" RETURNING SEQUENCE) AS CLOB(32K)) FROM

              XMLporder AS t WHERE POid = ?");

              db2_execute($stmt, array($id));

              list($po) = db2_fetch_array($stmt);

              echo $po;

              還請注意,PHP 應用程序代碼量達到最少,因為大部分業務邏輯和轉換位於查詢中。

              非 XML RDBMS


              1. $stmt = db2_prepare($conn, "SELECT POrder FROM sqlporder WHERE POid = ?");

                db2_execute($stmt, array($id));

                $sum = 0.0;

                while(list($po) = db2_fetch_array($stmt)) {

              2. 因為采購訂單存儲為 CLOB,我們需要使用 DOM 訪問每個產品及其數量和價格。使用簡單 DOM 從采購訂單中提取數據:



                $dom = simpleXML_load_string($po);

                foreach($dom->items->item as $item) {

                $cpid = (string) $item[pid'];

                $price = (float) $item[price'];

              3. 跟蹤 Html 表每一行中的總價:



                $sum += $price * (integer) $item[quantity'];

              4. 需要進行單獨查詢來查找每個貨品的名稱。



                $stmt2 = db2_prepare($conn, "SELECT Name FROM sqlproduct WHERE Pid = ?");

                db2_execute($stmt2, array($cpid));

                if($stmt2) {

                list($prodName) = db2_fetch_array($stmt2); ?>

















                $






                }

                }

                }

              代碼的關系版本向應用程序引入了較多的邏輯。

              報告客戶的訂購歷史記錄

              客戶可以單擊索引中的 Order history 鏈接,列出他們的所有采購訂單:

              圖 10. 訂購歷史記錄

              訂購歷史記錄

              DB2 Viper
              1. 使用 SQL/XML 返回按日期排序的客戶采購訂單。對於每個采購訂單,都將執行一個 XQuery,返回每個產品小計的格式化結果。



                $xquery =

                for $po in $t/purchaSEOrder

                let $items := for $item in $po/items/item

              2. 在 XQuery 內執行聯接以顯示每個產品的名稱,因為采購訂單僅存儲產品 ID、價格和數量:



                let $name := for $i in db2-fn:xmlcolumn("XMLPRODUCT.DESCRIPTION")/product

                where $i/@pid = $item/@pid return $i/description/name/text()

                return

                {xs:string($item/@quantity)} x @ ${xs:string($item/@price)} {$name}



                return



                Order #{xs:string($po/@id)} placed on {xs:string($po/@orderDate)}



                {$items}

                ;

                $stmt = db2_prepare($conn, "SELECT XMLSERIALIZE(XMLQUERY

                ($xquery' PASSING BY REF

                T.PORDER AS \"t\" RETURNING SEQUENCE) AS CLOB(32K))

                FROM XMLporder AS t

                ORDER BY POid DESC");

                db2_execute($stmt);

                while(list($po) = db2_fetch_array($stmt)) {

                echo $po; }

              非 XML RDBMS
              1. 在關系版本中,必須執行一個查詢來獲取每個采購訂單中產品的列表:



                $stmt = db2_prepare($conn, "SELECT POid, POrder FROM sqlporder

                ORDER BY POid DESC");

                db2_execute($stmt);

                while(list($POid, $po) = db2_fetch_array($stmt)) {

              2. 因為采購訂單在關系數據庫中存儲為 CLOB,我們必須使用 DOM 訪問訂單日期和各個產品。PHP 5 的 SimpleXML 功能在此會再次派上用場。



                $dom = simpleXML_load_string($po);

                ?>

                Order #

                placed on




                foreach($dom->items->item as $item) {

              3. 對於每個產品,必須查詢詳細信息,在本例中查詢其名稱:



                $stmt2 = db2_prepare($conn, "SELECT Name FROM sqlproduct WHERE Pid = ?");

                db2_execute($stmt2, array( (string) $item[pid'] ));

                while(list($prodName) = db2_fetch_array($stmt2)) {

                ?>

                 x @ $ 




                }

                }

                }

              XML 索引

              雖然我們沒有創建任何關系索引,但將創建一些 XML 索引來說明如何使用 DB2 原生 XML 支持從文檔中的任何元素或屬性創建索引。每個產品文檔都有一個惟一產品 ID 以及浏覽目錄時常常使用的其他重要信息,包括種類、品牌和名稱。對於產品 XML 列,將創建這四個索引。

              CREATE UNIQUE INDEX prod_pid ON XMLproduct(description) GENERATE KEY USING

              XMLPATTERN /product/@pid' AS SQL VARCHAR(10)

              CREATE INDEX prod_name ON XMLproduct(description) GENERATE KEY USING

              XMLPATTERN /product/description/name' AS SQL VARCHAR(128)

              CREATE INDEX prod_category ON XMLproduct(description) GENERATE KEY USING

              XMLPATTERN /product/description/category' AS SQL VARCHAR(128)

              CREATE INDEX prod_brand ON XMLproduct(description) GENERATE KEY USING

              XMLPATTERN /product/description/brand' AS SQL VARCHAR(128)

              正如您可以看到的,可以從屬性以及元素創建索引。

              設置運行應用程序的環境

              設置 apache 和 PHP

              首先需要設置 PHP 開發環境和 Web 服務器來運行服務器端 PHP 腳本。這些說明是圍繞 Windows 的,但是代碼也可以在 Linux 和其他類似 UNIX 的平台上運行,而不需要更改。有關如何設置使用 apache 來設置 PHP 模塊的信息,請參考 PHP 文檔。

              1. 確保安裝了 DB2 Version 8.2 或更高版本客戶機庫。 本篇文章發表於www.xker.com(小新)
              2. 從 http://httpd.apache.org/ 下載並安裝 Apache 最新的 2.0 版。對於開發工作,最好不要將 Apache 安裝為服務,因為您會發現將頻繁地重新啟動它。啟動 Apache 並導航到 http://localhost/,以確保 apache 正在運行。
              3. 下載 PHP 5 的最新穩定版本的 zip 包,然後將其解壓縮到 c:\PHP。
              4. 從同一頁面下載 PECL(PHP Extension Community Library,PHP 擴展公共庫)模塊集合。將此 zip 文件解壓縮到 c:\PHP\ext。
              5. 將 c:\php\php.ini-dist 復制到 c:\php\PHP.ini,然後用編輯器將其打開。
                1. 查找 extension_dir 設置並將其更改為:

                  extension_dir = "c:/PHP/ext/"
                2. 查找 Dynamic Extensions 部分並添加下列行:

                  extension=PHP_ibm_db2.dll

                  extension=PHP_soap.dll
              6. 用編輯器打開 apache 的配置文件 httpd.conf。
                1. 查找 Dynamic Shared Object (DSO) Support 部分,在 LoadModule 指令列表的後面添加下列行:

                  LoadModule php5_module "c:/php/PHP5apache2.dll"

                  AddType application/x-httpd-php .PHP

                  AddType application/x-httpd-php-source .PHPs

                  PHPIniDir "c:/PHP"
                2. 查找 DirectoryIndex 指令,將 index.PHP 添加到列表中:

                  DirectoryIndex index.PHP index.html index.Html.var
              7. 您可能希望刪除 apache 安裝的 htdocs 目錄(DocumentRoot 指令的值)中包含的文件。在 htdocs 目錄中創建一個新文件 info.PHP,內容為:

              8. 啟動 Apache 並導航到 http://localhost/info.php。如果向下滾動頁面時看到 ibm_db2 配置,則已經成功配置了 apache、PHP 和 ibm_db2 驅動程序!
              設置應用程序代碼

              嘗試運行附加的應用程序之前,確保具有包含 PHP 支持的 Web 環境。應用程序的前端可以在 Mozilla Firefox 中正確顯示;因此,當您使用其他浏覽器時可能會看到難看的頁面布局。請按照以下簡單步驟來設置和運行應用程序:

              1. 先下載本文結尾的 zip 文件,然後將其解壓縮到 htdocs 目錄(通常為 C:\Program Files\Apache Group\apache\htdocs)。進入 silvercastles 目錄。
              2. 在將要使用的數據庫服務器中,創建名為 silver 的數據庫。為了使 XML 功能可以與 DB2 Viper 一起使用,必須明確指定 Unicode 數據庫:

                CREATE DATABASE silver USING CODESET utf-8 TERRITORY us
              3. 如果要創建編目數據庫連接,必須在本地計算機中從 DB2 Command Window 內運行以下命令:

                CATALOG TCPIP NODE myNode REMOTE serverAddr SERVER serverPort

                CATALOG DB silver AT NODE myNode

                確保用數據庫服務器的主機名或 IP 地址及其 TCP/IP 端口(SVCENAME 數據庫管理器配置變量)分別替換 serverAddr 和 serverPort。如果未在服務器中設置 SVCENAME 變量,需要將其設置為空閒端口,然後重新啟動 DB2

                $ db2 UPDATE DBM CFG USING SVCENAME 12345

                $ db2stop ; db2start
              4. 編輯 config.php 並修改適當的值。如果需要,一定要對某些字符進行轉義,因為您在修改實際的 PHP 代碼。
                1. $basedir:silvercastles 目錄的路徑(使用正斜線,以避免對路徑進行轉義,如 C:/Program Files/Apache Group/apache/htdocs/silvercastles)
                2. $dbname:數據庫名稱
                3. $dbuser:允許連接數據庫的用戶名稱
                4. $dbpass:用戶密碼
                  如果使用編目數據庫連接,則執行到步驟 3。另外,還需要修改以下值:
                    1. $dbhost:數據庫服務器的主機名或 IP 地址
                    2. $dbport:服務器的端口號
                  1. 保存配置並將浏覽器指向 http://localhost/setup.PHP,以創建 XML 和關系表並插入數據。單擊 Continue 鏈接訪問在線商店。
            1. 上一頁:
            2. 下一頁:
            Copyright © 程式師世界 All Rights Reserved