程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> PEARMDB數據庫抽象層——一次編寫—隨處運行

PEARMDB數據庫抽象層——一次編寫—隨處運行

編輯:關於PHP編程

Write once - run anywhere 一次編寫——隨處運行 這是Java的一句行銷口號,但是它同時也是PHP的關鍵特性之一。許多商業模型依賴於操作系統無關性來保證產品能夠銷售給廣泛的客戶群體。因而,為什麼要把你自己綁在某種數據庫廠商的身上呢?數據庫抽象層使得你能夠與數據庫獨立的開發你的應用程序。但是,通常情況下它們對性能的影響超過了你所希望的,要麼他們並不足夠抽象以消除所有和特定數據庫相關的代碼。 這篇文章將教給我什麼? 這篇文章將對數據庫抽象包 PEAR MDB 有一個很好的介紹。文章的焦點將是對 MDB 超越類似包所提供的更先進的特性,例如數據類型抽象和基於 XML 的 schema 管理。對 PHP 和 SQL 的基本理解是推薦的。 為什麼另外再要一個數據庫類? 通常, web 工程在客戶已經確定了要使用那種 RDBMS (關系型數據庫管理系統)之後被添加給已經存在的 IT 基礎結構。即使那並不是因為不同的預算可能影響的你選擇何種數據用於部署的情況。最終,你作為開發者可能簡單的偏好於不把自己綁在某個廠商身上。自此,意味著給每個支持的數據保持版本或者犧牲更多性能但是獲得多於必須的易用性:走入 PEAR MDB 吧。 MDB 是著眼於使得編寫 RDBMS 無關的 PHP 程序成為簡單的過程的數據庫抽象層。大部分其他的 PHP 的所謂數據庫抽象層緊緊給所有支持的數據庫提供了一個公用 API 以及非常有限的抽象(大部分只是針對序列的)。MDB 另一方面能夠用來抽象所有數據庫發送和接收的數據。甚至數據庫 schema 都能被定義為 RDBMS 無關的格式。但是它提供這些功能的同時仍然保持了很高的性能以及簡單易用。這是通過深入觀察兩個流行的數據庫抽象層,PEAR DB 和 Metabase, 之後並且對它們進行了融合後獲得的。而且在融合過程中,趁著這個機會清理了它們融合後的 API 以及任何影響性能的設計。 MDB 是怎樣出現的? 早在 2001 年的秋天,我就在尋找一種可能能夠讓我公司的程序框架與 RDBMS 獨立的數據庫抽象包。這個目標是把特定數據庫相關的代碼數量減少到零。我發現提供這樣的功能的唯一的一個包是 Metabase。但是 Metabase有一些部分是因為為了和 PHP3 兼容的讓人不舒服的 API。盡管如此,我們決定 Metabase 是我們唯一的選擇。但是即使是在給 Metabase 增加了一個性能改進的補丁之後,我們仍然感到我們放棄了太多的性能。我們在 2001 年的 PHP 國際會議上碰到了 Metabase 的作者,並且我們談論了讓像 Metabase 這樣的東西成為 PEAR 工程一部分的好處。後來不久,在 PEAR 郵件列表上就 PEAR DB 和 Metabase 融合的可能的好處又開始了一場討論。在我們公司進行了許多討論之後,我們決定承擔這個任務。數個月的艱辛工作之後,我們現在有了 MDB 的第一個穩定的 release。 MDB 給你提供了什麼? MDB 結合了 PEAR DB 和 Metabase 的大部分特性。實際上,PEAR DB 的特性中唯一不再存在的是作為結果集返回一個對象。我們放棄了這個特性是因為這個特性不常用而且對於性能的損失是非常明顯的。許多開發上的時間用在了使得 API 盡可能的好用。最終,MDB 非常高地提供了這些功能至少和 PEAR DB 一樣快而且比 Metabase 快很多。這些最重要地特性的列表: OO 風格的 API 預准備的查詢模擬 給所有傳遞進來以及從數據庫中取出的數據的完全的數據類型抽象(包括 LOB 支持) 事務支持 數據庫/表/索引/序列創建/拋棄/改變 RDBMS 無關的數據庫 schema 管理 繼承進 PEAR 框架(PEAR 安裝程序,PEAR 錯誤處理等) 那麼它如何使用呢? MDB 提供了一些非常先進的抽象特性。記住這些特性只是供選擇的是很重要的。但是在編寫 RDBMS 無關的 PHP 程序時使用它們是非常重要的。一個展示使用 MDB 是多麼簡單的例子在文章的結尾的 "鏈接和文獻" 部分。如前面所說,文章的焦點是介紹使得 MDB 與其他 PHP 數據庫抽象層不同的那些特性。你可以在隨本期文章一同包裝的 CD 中找到所有這些例子腳本的代碼。 但是,首先我們需要把 MDB 安裝上去。使用 PEAR 安裝程序這其實非常容易。我不能在這篇文章中完整的講述 PEAR 安裝程序但是我聽說下一期將非常詳細的討論 PEAR 框架的裡裡外外。讓安裝程序運行於 Windows 的工作在進行當作但是支持仍然有一點古怪。對於 *nix 系統你需要 PHP 的 CGI 版本安裝在了你的系統並且簡單地運行下面地命令: lynx -source go-pear.org|php 在安裝完成之後你只需要再輸入一行命令那麼就全部搞定了。 pear install MDB 如果前面的過程對你來說不管用,總是有從 PEAR MDB 主頁中直接獲得包的選項。URL 列於文章的最後。 利用數據類型抽象 因為大部分數據庫傾向於有一些個性或者怪癖,對於MDB來說把這些不同之處給開發者隱藏起來非常重要。MDB 通過定義自己的內部數據類型來達到這點:text,boolean,integer,decimal,float,date,time,time stamp,large objects(文件)。所有傳遞給數據庫和從數據庫獲取的數據都能轉換成 MDB 的內部格式或者從數據庫的內部格式轉化回來。本節相關的例子腳本能夠再 datatype 目錄中找到。讓我們看看下面的查詢: $session = 098f6bcd4621d373cade4e832627b4f6; // set time out to 30 minutes $timeout = time()+60*30; // SELECT query showing how the datatype conversion works $query = SELECT createtime, user_id FROM sessions; $query .= WHERE session = .$session; $query .= AND lastaccess < .$timeout; 這個查詢如果發送給數據庫的話八成要失敗。原因是存儲在 $name 中的值需要轉換為正確的字符串格式。這也許意味著 $name 的內容可能有特殊的轉義字符或者被引號包圍。PEAR DB 為此提供了方法 DB:.quote()。在 MDB 中這個方法叫 MDB::getTextValue()。不同之處是 MDB 給每種前面所列的數據類型都提供了這樣的函數。因而我們也能夠把 $timeout 轉換為正確的格式。 // convert $timeout to the MDB timestamp format $timeout = MDB_date::unix2Mdbstamp($timeout); // SELECT query showing how the datatype conversion works $query = SELECT createtime, user_id FROM sessions; $query .= WHERE session = .$mdb->getTextValue($session); $query .= AND lastaccess < .$mdb->getTimestampValue($timeout); 為了作個演示,讓我們假定我僅僅想要獲取第一行。MDB::queryRow() 獲得第一行,它釋放結果集並且返回其內容,因而它正是我們所要的。 $result = $mdb->queryRow($query); 但是不同的 RDBMS 返回像日期這樣的數據時用的格式是不同的。因此,如果我們然後要對一些數據進行計算,不管選擇的 RDBMS 是什麼,把數據以相同的格式返回是重要的。這個可以由 MDB 半自動地完成。你所有需要做的是告訴你的結果列將是什麼樣的類型,MDB將處理轉換的工作。最簡單的辦法是把這樣的信息傳遞給查詢函數。 $types = array(timestamp, integer); $result = $mdb->queryRow($query, $types); 這告訴 MDB 結果集的第一列類型是 timestamp 以及第二列是integer。所有查詢函數能夠接受這樣的元信息作為可選的參數。數據還能事後用 MDB::setResultTypes() 來設置。取決於數據獲取於的數據庫,它然後將被相應的轉換返回的數據。MDB 內部的 timestamps 的數據格式是遵循 ISO 8601 標准的。其他像 PEAR::Date 這樣的包能夠處理這種格式。MDB 還在 MDB_Date 類中提供了一些數據格式轉換函數,它們能夠被可選的包含。 因為相當多的 RDBMS 以相同的方法返回整數數據,沒有必要轉換整數數據。因而,為了獲得稍許的性能改進你能夠這麼做: $types = array(timestamp); $result = $mdb->queryRow($query, $types); 這樣只有結果集的第一列會被轉換。當然,如果 MDB 用於返回整數不同的數據庫,這可能成為一個問題。然而,稍許的性能改善可能並不值得冒這個風險。但是再一次的,它顯示了這些特性的使用僅僅是供選擇的。 Listing 1 展示了一個使用預准備的查詢的例子。如果你必須運行大量查詢而唯一的差別是數據傳遞給數據庫,但是查詢的結構還是一樣的,這些能夠相當的方便。高級的數據庫能夠在內存中儲存解析好的查詢來加速性能。 Listing 1 $alldata = array( array(1, one, un), array(2, two, deux), array(3, three, trois), array(4, four, quatre) ); $p_query = $mdb->prepareQuery(INSERT INTO numbers VALUES (?,?,?)); $param_types = array(integer, text, text); foreach ($alldata as $row) { $mdb->execute($p_query, NULL, $row, $param_types); } 在 $alldata 中儲存的所有四個數組將用於 execute 語句。數據將自動被轉換為正確的格式。因為這是一個插入語句,MDB::execute() 的第二個參數被設置為 NULL 因為我們將沒有任何結果列需要我們設置數據類型。 在支持的數據類型中還有 LOB (大對象),它使得我們能夠在數據庫中儲存文件。二進制文件儲存在 BLOB (二進制大對象)中而且普通文本文件儲存在 CLOB (字符大對象)中。在 MDB 中你僅僅能夠使用預准備的 INSERT 和 UPDATE 查詢儲存 LOB。使用 MDBA::setParamBlob() 或者 MDB::setParamClob() 你能夠設置預准備查詢的 LOB 域的值。兩個函數都預期傳遞一個 LOB 對象,而它能夠使用 MDB::createLob() 創建。 $binary_lob = array( Type => inputfile, FileName => ./myfile.gif ); $blob = $mdb->createLob($binary_lob); $character_lob = array( Type => data, Data => this would be a very long string container the CLOB data ); $clob = $mdb->createLob($character_lob); 如你能看到的,MDB::createLob() 被傳遞一個關系數組。Type 鍵的值可能是以下中的一個:data, inputfile 或者 outputfile。前兩個用於你想要把 LOB 寫入數據庫的時候。如果你有一個儲存在變量中的 LOB,你應當在 需要使用 inputfile 時從文件直接讀取 LOB。最後,outpufile 應當在你想要從數據庫中讀取 LOB 時使用。取決於你是否使用數據或者 inp

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved