使用Oracle數(shù)據(jù)庫(kù)實(shí)現(xiàn)Python數(shù)據(jù)持久
盡管Python 很快在開發(fā)人員之中普及,但長(zhǎng)久以來(lái) Oracle 數(shù)據(jù)庫(kù)一直是最出色的企業(yè)級(jí)數(shù)據(jù)庫(kù)。采用有效的方式將這兩者結(jié)合在一起是比較令人感興趣的主題,但這實(shí)際上是真正的挑戰(zhàn),因?yàn)槎叨家冻龊芏唷?/P>
盡管受到警告,但本文并不會(huì)對(duì)最杰出的 Python 和 Oracle 數(shù)據(jù)庫(kù)特性進(jìn)行概述,而是提供一系列獨(dú)立的示例。本文借助一個(gè)示例讓您了解如何采用互補(bǔ)的方法嘗試將這兩種技術(shù)結(jié)合使用。尤其是,本文將指導(dǎo)您利用 PL/SQL 存儲(chǔ)過(guò)程(在 Python 腳本中編排其調(diào)用)創(chuàng)建 Oracle 支持的 Python 應(yīng)用程序,該應(yīng)用程序在 Python 和數(shù)據(jù)庫(kù)中實(shí)施業(yè)務(wù)邏輯。
正如您將在本文中學(xué)習(xí)到的,即使是輕型的 Oracle 數(shù)據(jù)庫(kù) 10g 快捷版 (XE) 也可以得到有效利用,作為數(shù)據(jù)驅(qū)動(dòng)的 Web 應(yīng)用程序的數(shù)據(jù)庫(kù)后端,其前端層使用 Python 構(gòu)建。特別是,Oracle 數(shù)據(jù)庫(kù) XE 支持 Oracle XML DB,這是構(gòu)建 Web 應(yīng)用程序時(shí)通常需要的一組 Oracle 數(shù)據(jù)庫(kù) XML 技術(shù)。
示例應(yīng)用程序
在用戶使用您的應(yīng)用程序時(shí)收集有關(guān)用戶執(zhí)行操作的信息成為一種比較流行的接收用戶反饋的機(jī)制。通常,相對(duì)于讓用戶明確表達(dá)偏好的任何調(diào)查來(lái)說(shuō),并入在線應(yīng)用程序中的點(diǎn)擊跟蹤工具可以為您提供有關(guān)用戶偏好的大量信息。
舉一個(gè)簡(jiǎn)單的例子,假設(shè)您想從“OTN — 新文章 RSS”頁(yè)面中選取三個(gè)最新的 Oracle 技術(shù)網(wǎng) (OTN) 文章標(biāo)題,并將這些鏈接放到您的站點(diǎn)上。然后,您希望收集有關(guān)用戶在您的站點(diǎn)上跟隨這些鏈接中的每個(gè)鏈接的次數(shù)的信息。這就是我們的示例將要做的?,F(xiàn)在,讓我們?cè)囍迦绾螌?shí)現(xiàn)所有這些功能。首先,必須決定如何在應(yīng)用程序?qū)又g分發(fā)業(yè)務(wù)邏輯。實(shí)際上,決定如何在應(yīng)用程序?qū)又g分發(fā)業(yè)務(wù)邏輯可能是規(guī)劃數(shù)據(jù)庫(kù)驅(qū)動(dòng)的應(yīng)用程序最具挑戰(zhàn)性的部分。盡管執(zhí)行業(yè)務(wù)邏輯通常有多種方法,但是您的工作是找到最有效的方法。作為一般的經(jīng)驗(yàn),當(dāng)規(guī)劃數(shù)據(jù)庫(kù)驅(qū)動(dòng)的應(yīng)用程序時(shí),您應(yīng)該認(rèn)真考慮數(shù)據(jù)庫(kù)中關(guān)鍵數(shù)據(jù)處理邏輯的實(shí)現(xiàn)。這種方法可以幫助您削減與在 Web 服務(wù)器和數(shù)據(jù)庫(kù)之間發(fā)送數(shù)據(jù)相關(guān)的網(wǎng)絡(luò)開銷,并且可以減輕 Web 服務(wù)器的負(fù)擔(dān)。
將所有這些理論應(yīng)用到我們的示例上,例如,將獲得插入到數(shù)據(jù)庫(kù)中的文章詳細(xì)信息的負(fù)擔(dān)放到在數(shù)據(jù)庫(kù)中創(chuàng)建的存儲(chǔ)過(guò)程上,這樣 Web 服務(wù)器不必再處理與維護(hù)數(shù)據(jù)完整性有關(guān)的任務(wù)。這在實(shí)踐中的意義是您不必編寫特定 Python 代碼,這些代碼負(fù)責(zé)跟蹤數(shù)據(jù)庫(kù)中是否存在與其鏈接被點(diǎn)擊的文章有關(guān)的記錄,如果不存在,則插入該記錄,然后從“OTN — 新文章 RSS”頁(yè)面中獲取所需的所有詳細(xì)信息。通過(guò)讓數(shù)據(jù)庫(kù)自己跟蹤此類事情,您可以獲得具有更高可擴(kuò)展性且更不易出錯(cuò)的解決方案。在本例中,Python 代碼將只負(fù)責(zé)從 RSS 頁(yè)面獲取文章鏈接,并在用戶單擊某個(gè)文章鏈接時(shí)向數(shù)據(jù)庫(kù)發(fā)送一條消息。
圖 1 給出了示例組件如何彼此交互以及如何與外部源交互的圖形描述。
圖 1:示例應(yīng)用程序工作原理的高級(jí)視圖。
本文的其余部分介紹如何實(shí)現(xiàn)此示例應(yīng)用程序。有關(guān)如何設(shè)置和啟動(dòng)此示例的簡(jiǎn)要描述,可以參考示例代碼根目錄下的 readme.txt 文件。
準(zhǔn)備工作環(huán)境
要構(gòu)建此處討論的示例,您需要安裝以下軟件組件(參見 Downloads portlet)并使其在您的系統(tǒng)中正常工作:
Apache HTTP Server 2.x
Oracle 數(shù)據(jù)庫(kù) 10g 快捷版
Python 2.5 或更高版本
mod_python 模塊
cx_Oracle 模塊
有關(guān)如何安裝上述組件的詳細(xì)說(shuō)明,可以參考另一篇 OTN 文章“為 Python Server Pages 和 Oracle 構(gòu)建快速 Web 開發(fā)環(huán)境”(作者:Przemyslaw Piotrowski)。
#p#
設(shè)計(jì)基礎(chǔ)數(shù)據(jù)庫(kù)
一般來(lái)說(shuō),最好從設(shè)計(jì)基礎(chǔ)數(shù)據(jù)庫(kù)開始。假設(shè)您創(chuàng)建了一個(gè)用戶模式并授予其創(chuàng)建和操作模式對(duì)象所需的所有權(quán)限,那么第一步就是創(chuàng)建基礎(chǔ)表。在這種特殊情況下,您將需要一個(gè)唯一的名為 otn_articles_rss 的表,創(chuàng)建該表的方式如下:
CREATE TABLE otn_articles_rss ( |
下一步是設(shè)計(jì)一個(gè)將在 Python 代碼中調(diào)用的名為 count_clicks 的存儲(chǔ)過(guò)程,它更新 otn_articles_rss 表中的數(shù)據(jù)。繼續(xù) count_clicks 過(guò)程之前,您必須先回答以下問(wèn)題:當(dāng) count_clicks 嘗試更新尚未插入到 otn_articles_rss 表中的文章記錄的 clicks 字段時(shí),會(huì)發(fā)生什么情況呢?假設(shè)一個(gè)新項(xiàng)目剛剛添加到 RSS 頁(yè)面,然后指向該項(xiàng)目的鏈接出現(xiàn)在您的站點(diǎn)上。當(dāng)有人單擊該鏈接時(shí),系統(tǒng)將從負(fù)責(zé)處理指向 OTN 文章的鏈接上執(zhí)行的單擊次數(shù)的 Python 代碼中調(diào)用 count_clicks PL/SQL 過(guò)程。顯然,處理第一次單擊時(shí),在 count_clicks 過(guò)程中發(fā)出的 UPDATE 語(yǔ)句將失敗,因?yàn)楝F(xiàn)在還沒有要更新的行。
要適應(yīng)此類情況,您可以在 count_clicks 過(guò)程中實(shí)現(xiàn)一個(gè) IF 塊,如果由于 UPDATE 找不到指定的記錄而將 SQL%NOTFOUND 屬性設(shè)置為 TRUE 時(shí),該塊會(huì)發(fā)揮作用。在該 IF 塊中,只要指定了 guid 和單擊次數(shù),您就可以先將一個(gè)新行插入到 otn_articles_rss 表中。之后,您應(yīng)該提交這些更改,以便這些更改立即可用于其他用戶會(huì)話,這些會(huì)話可能也需要更新新插入的文章記錄的 clicks 字段。最后,您應(yīng)該更新該記錄,設(shè)置其 title、pubDate 和 link 字段。該邏輯可以作為一個(gè)單獨(dú)的過(guò)程(比如 add_article_details)來(lái)實(shí)現(xiàn),該過(guò)程的創(chuàng)建方式如下:
CREATE OR REPLACE PROCEDURE add_article_details (gid VARCHAR2, clks NUMBER) AS 'http://feeds.delicious.com/v2/rss/OracleTechnologyNetwork/otntecharticle').getXML(), |
正如您所見,該過(guò)程接受兩個(gè)參數(shù)。gid 是其鏈接受到單擊的文章的 guid。clks 是文章查看總次數(shù)的增量。在該過(guò)程主體中,您獲得 RSS 文檔的所需部分作為 XMLType 實(shí)例,然后提取信息,之后該信息將立即用于填充 otn_articles_rss 中與正在處理的 RSS 項(xiàng)目關(guān)聯(lián)的記錄。
借助 add_article_details,您可以繼續(xù)下一環(huán)節(jié),按照如下方式創(chuàng)建 count_clicks 過(guò)程:
CREATE OR REPLACE PROCEDURE count_clicks (gid VARCHAR2, clks NUMBER) AS BEGIN |
事務(wù)考慮事項(xiàng)
在上面清單中所示的 count_clicks 存儲(chǔ)過(guò)程中,注意 COMMIT 的使用要緊跟在 INSERT 語(yǔ)句之后。最重要的是,之后要調(diào)用 add_article_details,其執(zhí)行時(shí)間可能較長(zhǎng)。通過(guò)在這個(gè)階段提交,新插入的文章記錄立即用于其他可能的更新,否則要等待 add_article_details 完成。
考慮以下示例。假設(shè) RSS 頁(yè)面剛剛更新并且一個(gè)全新的文章鏈接變?yōu)榭捎?。接下?lái),兩個(gè)不同的用戶加載您的頁(yè)面并幾乎同時(shí)單擊這個(gè)新鏈接。因此,將進(jìn)行兩個(gè)對(duì) count_clicks 的同時(shí)調(diào)用。在本例中,首先發(fā)生的調(diào)用將一條新記錄插入到 otn_articles_rss 表中,然后它將調(diào)用 add_article_details。雖然正在執(zhí)行 add_article_details,但對(duì) count_clicks 的另一個(gè)調(diào)用可以成功執(zhí)行更新操作,增加總單擊次數(shù)。但是,如果此處忽略了 COMMIT,那么第二個(gè)調(diào)用將找不到用于更新的行,因此嘗試執(zhí)行另一個(gè)插入。事實(shí)上,這將導(dǎo)致不可預(yù)測(cè)的結(jié)果。它將導(dǎo)致獨(dú)特的違反約束的錯(cuò)誤,并且會(huì)丟失將第二次 count_clicks 調(diào)用進(jìn)行的更新。
此處最令人感興趣的部分是在 count_clicks 過(guò)程主體結(jié)尾處執(zhí)行另一個(gè) COMMIT 操作。正如您所猜測(cè)的,需要在這個(gè)階段提交以便從更新的記錄中去除鎖定,從而使該記錄立即可用于其他會(huì)話執(zhí)行的更新。有些人可能會(huì)說(shuō)這個(gè)方法降低了靈活性,使客戶端無(wú)法根據(jù)自己的判斷提交或回滾事務(wù)。但是,在這種特殊的情況下,這并不是一個(gè)大問(wèn)題,因?yàn)闊o(wú)論如何從調(diào)用 count_clicks 開始的事務(wù)都應(yīng)該立即提交。這是因?yàn)楫?dāng)用戶單擊某個(gè)文章鏈接以離開您的頁(yè)面時(shí),始終會(huì)調(diào)用 count_clicks。
構(gòu)建前端層
既然已經(jīng)創(chuàng)建了存儲(chǔ)過(guò)程并且準(zhǔn)備好在應(yīng)用程序中使用,那么您必須弄清如何從前端層編排在數(shù)據(jù)庫(kù)中實(shí)現(xiàn)的所有這些應(yīng)用程序邏輯片段所執(zhí)行的整個(gè)操作流。這就是 Python 派上用場(chǎng)的地方了。
我們先來(lái)看一個(gè)簡(jiǎn)單的實(shí)現(xiàn)。為了開始,您必須編寫一些 Python 代碼,這些代碼將負(fù)責(zé)從“OTN — 新文章 RSS”頁(yè)面獲取數(shù)據(jù)。然后,您將需要開發(fā)一些代碼,這些代碼將處理在 Web 頁(yè)面中的 OTN 文章鏈接上執(zhí)行的單擊。最后,您將需要構(gòu)建該 Web 頁(yè)面本身。為此,您可能會(huì)使用 Python 的一種服務(wù)器端技術(shù),比如 Python Server Pages (PSP),這使得將 Python 代碼嵌入到 HTML 中成為可能。
為了編寫 Python 代碼,您可以使用您喜歡的文本編輯器,如 vi 或記事本。創(chuàng)建一個(gè)名為 oraclepersist.py 的文件,然后在其中插入以下代碼,將該文件保存到 Python 解釋器可以找到的位置:
import cx_Oracle import urllib2 latest.append(dict(zip(inxs,[item.getElementsByTagName(inx)[0].firstChild.data for inx in inxs]))) |
正如您所猜測(cè)的,上面所示的 getRSS 函數(shù)將用來(lái)從 RSS 頁(yè)面獲取數(shù)據(jù),并將該數(shù)據(jù)作為一個(gè) DOM 對(duì)象返回。getLatestItems 專門用來(lái)處理該 DOM 文檔,將該文檔轉(zhuǎn)換為 Python dictionary 對(duì)象。
在 getLatestItems 函數(shù)中,注意列表內(nèi)涵(一個(gè)新的 Python 語(yǔ)言特性)的使用,它提供了一種出色的方法,可顯著簡(jiǎn)化數(shù)據(jù)處理任務(wù)的編碼。
下一步涉及一些代碼的創(chuàng)建,這些代碼將處理在指向 OTN 文章的鏈接上執(zhí)行的單擊,這些鏈接是從“OTN — 新文章 RSS”頁(yè)面中獲取并放置到 Web 頁(yè)面上的。為此,您可以開發(fā)另一個(gè)自定義 Python 函數(shù)(比如說(shuō) processClick),每次用戶單擊您 Web 頁(yè)面上的 OTN 文章鏈接時(shí)都會(huì)調(diào)用該函數(shù)。要實(shí)現(xiàn) processClick,將以下代碼添加到 oraclepersist.py:
def processClick(guid, clks = 1): db = cx_Oracle.connect('usr', 'pswd', '127.0.0.1/XE') |
以上代碼提供了實(shí)際運(yùn)行的 cx_Oracle 的一個(gè)簡(jiǎn)單示例。它首先連接到基礎(chǔ)數(shù)據(jù)庫(kù)。然后,它獲得一個(gè) Cursor 對(duì)象,之后使用該對(duì)象的 execute 方法調(diào)用在之前的“設(shè)計(jì)基礎(chǔ)數(shù)據(jù)庫(kù)”部分討論的 count_clicks 存儲(chǔ)過(guò)程。
現(xiàn)在,您可以繼續(xù)下一環(huán)節(jié),構(gòu)建 Web 頁(yè)面。由于這是僅用于演示的應(yīng)用程序,因此該頁(yè)面可能非常簡(jiǎn)單,只包含從 RSS 頁(yè)面獲得的鏈接。在 APACHE_HOME/htdocs 目錄中,創(chuàng)建一個(gè)名為 clicktrack.psp 的文件,然后在其中插入以下代碼:
﹤html﹥ |
正如您所見,以上文檔包含幾個(gè)嵌入的 Python 代碼塊。在第一個(gè)塊中,您從之前按照該部分所述創(chuàng)建的 oraclepersist 模塊調(diào)用函數(shù),獲得列表的一個(gè)實(shí)例,該列表的項(xiàng)目代表三篇最新的 OTN 文章。然后,在 for 循環(huán)中循環(huán)該列表,為該列表中存在的每個(gè)文章項(xiàng)目生成一個(gè)鏈接。令人感興趣的是,盡管這些鏈接中的每個(gè)鏈接都引用相應(yīng)的 OTN 文章地址,但是鏈接的 onclick 處理程序?qū)?dòng)態(tài)修改鏈接到 dispatcher.psp 頁(yè)面的目標(biāo),該目標(biāo)需要在 APACHE_HOME/htdocs 目錄中創(chuàng)建。將兩個(gè)參數(shù)(即 guid 和 url)附加到每個(gè)動(dòng)態(tài)生成的鏈接,向 dispatcher.psp 提供有關(guān)正在加載的文章的信息。
以下是 dispatcher.psp 的代碼:
﹤html﹥ |
在以上代碼中,借助 FieldStorage 類的幫助訪問(wèn)了附加到 URL 的參數(shù),該類來(lái)自 mod_python 網(wǎng)頁(yè)上提供的 Mod_python 手冊(cè)中描述的 util 模塊。然后,從我們的 oraclepersist 自定義模塊中調(diào)用 processClick 函數(shù),將從 URL 中提取的 guid 作為第一個(gè)參數(shù)傳遞,將 1(意味著一次單擊)作為第二個(gè)參數(shù)傳遞。最后,將您的瀏覽器重定向到要加載的文章的位置。
現(xiàn)在,可以測(cè)試這個(gè)應(yīng)用程序了。由于您處理的是實(shí)時(shí)數(shù)據(jù),因此您必須連接到互聯(lián)網(wǎng)。建立連接之后,將瀏覽器指向 http://localhost/clicktrack.psp。因此,應(yīng)該出現(xiàn)一個(gè)包含指向 OTN 最新文章的三個(gè)鏈接的簡(jiǎn)單 Web 頁(yè)面。如圖 2 所示。
圖 2:這是加載時(shí)的應(yīng)用程序頁(yè)面。
單擊任一文章鏈接并查看所發(fā)生的情況。從用戶的角度,您將只看到文章正加載到瀏覽器中,如圖 3 所示。
圖 3:當(dāng)跟隨應(yīng)用程序頁(yè)面上的文章鏈接時(shí),用戶只能看到文章本身。
負(fù)責(zé)收集有關(guān)單擊信息的代碼將在后臺(tái)運(yùn)行。為了確保該代碼已經(jīng)這樣操作,您可以連接到基礎(chǔ)數(shù)據(jù)庫(kù)并發(fā)出以下查詢:
SELECT * FROM otn_articles_rss;
甚至在完全加載文章文檔之前,上述代碼應(yīng)該輸出一個(gè)包含有關(guān)正在加載的文章信息的行,在 clicks 字段中顯示 1。隨后對(duì)此鏈接進(jìn)行的每個(gè)單擊將使 clicks 字段的值增加 1。
#p#
采用Pythonic 方法
在前面部分中編寫的代碼結(jié)構(gòu)與采用 Pythonic 方法實(shí)現(xiàn)的代碼看起來(lái)不太相同。尤其是,您按照一定的順序?qū)崿F(xiàn)了一組將從在 HTML 中嵌入的代碼調(diào)用的函數(shù),將一個(gè)函數(shù)返回的結(jié)果用作另一個(gè)函數(shù)的參數(shù)。實(shí)際上,這是采用任何其他腳本語(yǔ)言(比如說(shuō) PHP)結(jié)構(gòu)化您的代碼的方式。
盡管 Python 的真正功能在于它能夠隱藏令人厭煩的實(shí)現(xiàn)詳細(xì)信息,從而提供一個(gè)簡(jiǎn)單、優(yōu)美而有效的編碼解決方案。字典、列表和列表內(nèi)涵是常用的 Python 內(nèi)置類型,在處理結(jié)構(gòu)化數(shù)據(jù)時(shí)可以顯著簡(jiǎn)化您的代碼。返回在前面部分中討論的 oraclepersist.py 腳本,對(duì)其進(jìn)行升級(jí),以便最大程度地利用這些杰出的 Python 語(yǔ)言工具。為了避免混淆,您可以將修訂保存在一個(gè)單獨(dú)的名為 oraclepersist_list.py 的文件中:
import cx_Oracle import urllib2 |
從以上代碼可以看出,利用列表內(nèi)涵(一種非常有效的結(jié)構(gòu)化應(yīng)用程序數(shù)據(jù)的機(jī)制)可以顯著減少代碼總量。此外,客戶端也不必顯式調(diào)用模塊函數(shù)。因此,您現(xiàn)在可以重新編寫按照前面部分所述嵌入在 clicktrack.psp 中的 Python 代碼塊,如下所示:
... |
盡管現(xiàn)在它更為簡(jiǎn)潔,但用戶不需要進(jìn)行任何更改。
但是,有人可能會(huì)說(shuō)將 PSP 頁(yè)面中的代碼與其后端連接實(shí)在不是一個(gè)靈活的方法。例如,將要顯示的鏈接數(shù)量以及要使用的 RSS 地址硬編碼到 oraclepersist_list.py 腳本中,借助這個(gè)新的語(yǔ)法,您無(wú)法根據(jù)需要?jiǎng)討B(tài)更改這些參數(shù)。要解決此問(wèn)題,可以將列表內(nèi)涵封裝在 oraclepersist_list.py 腳本中的某個(gè)函數(shù)中,如下所示:
... |
正如您所見,以上代碼仍然利用了基于使用列表內(nèi)涵、列表和字典的高級(jí)語(yǔ)法,從而允許在 clicktrack.psp 頁(yè)面中動(dòng)態(tài)更改參數(shù)。以下代碼片段將闡釋現(xiàn)在如何顯式指定要顯示的文章鏈接數(shù)量:
... |
使用面向?qū)ο蟮姆椒?/STRONG>
盡管 Python 中的面向?qū)ο缶幊?(OOP) 是完全可選的,但利用該范例可以最大程度地減少冗余,高效地自定義現(xiàn)有代碼。與其他現(xiàn)代語(yǔ)言一樣,Python 允許您使用類封裝邏輯和數(shù)據(jù),簡(jiǎn)化了數(shù)據(jù)定義和數(shù)據(jù)操作。
回到在前面部分中討論的 oraclepersist_list.py 腳本,將 processClick 函數(shù)替換為如下所示的 HandleClick 類:
... |
假設(shè)您將修訂保存在 oraclepersist_class.py 文件中,更新后的 dispatcher.psp 現(xiàn)在可能如下所示:
... |
下面您創(chuàng)建 HandleClick 類的一個(gè)實(shí)例,然后調(diào)用它的 processClick 方法,正確傳遞參數(shù),就像您之前所做的那樣。
在此處所討論的 HandleClick 類中,特別令人感興趣的是特殊類方法 methods __init__ 和 __del__ 的使用。與其他特殊方法一樣,您從不直接調(diào)用它們。相反,Python 隱式調(diào)用它們以響應(yīng)在實(shí)例生命周期期間發(fā)生的某些事件。因此在創(chuàng)建實(shí)例時(shí)調(diào)用 __init__ 構(gòu)造函數(shù),在銷毀實(shí)例之前調(diào)用 __del__ 析構(gòu)函數(shù)。
在上面的示例中,您在構(gòu)造函數(shù)中連接到數(shù)據(jù)庫(kù)并在析構(gòu)函數(shù)中關(guān)閉該連接。但在某些情況下,采用這些方法實(shí)現(xiàn)更多操作可能是非常令人感興趣的。例如,您可能希望在銷毀實(shí)例之前從析構(gòu)函數(shù)中發(fā)出 SQL 語(yǔ)句。以下代碼片段將闡釋如何重新編寫 HandleClick 類,以便從析構(gòu)函數(shù)中而不是從某個(gè)顯式調(diào)用的類方法中調(diào)用 count_clicks 存儲(chǔ)過(guò)程:
... class HandleClick: |
正如您所見,更新的 HandleClick 類中不再有 processClick。相反,客戶端代碼應(yīng)調(diào)用 addArticleClick,該函數(shù)用要傳遞給 count_clicks 存儲(chǔ)過(guò)程的參數(shù)填充該類的屬性 params dictionary,將從析構(gòu)函數(shù)中調(diào)用 count_clicks 存儲(chǔ)過(guò)程。因此,現(xiàn)在您可以重新編寫嵌入在 dispatcher.psp 頁(yè)面中的 Python 代碼塊,如下所示:
... |
注意,此處使用 del 語(yǔ)句取消包含綁定對(duì) HandleClick 類的某個(gè)實(shí)例的引用的 h 變量。由于這是對(duì)該實(shí)例的唯一引用,因此之后 Python 將使用一種名為垃圾回收的機(jī)制隱式刪除該實(shí)例。刪除后,將自動(dòng)觸發(fā) __del__ 析構(gòu)函數(shù),執(zhí)行 SQL 語(yǔ)句,然后關(guān)閉連接。
上面的示例極好地說(shuō)明了采用 Python 開發(fā)面向?qū)ο蟮拇a時(shí)使用特殊方法可以獲取的優(yōu)勢(shì)。在這個(gè)特殊示例中,客戶端代碼只負(fù)責(zé)為要針對(duì)數(shù)據(jù)庫(kù)發(fā)出的查詢?cè)O(shè)置參數(shù),而 Python 隱式執(zhí)行其余操作。
結(jié)論
正如您在本文中所學(xué)到的,開發(fā)一個(gè)可擴(kuò)展的數(shù)據(jù)庫(kù)驅(qū)動(dòng)的 Web 應(yīng)用程序需要進(jìn)行較良好的規(guī)劃。繼續(xù)構(gòu)建應(yīng)用程序組件和編寫代碼之前,您必須首先決定可以在數(shù)據(jù)庫(kù)中實(shí)現(xiàn)的應(yīng)用程序邏輯的數(shù)量以及可以在前端層實(shí)現(xiàn)的操作。
設(shè)計(jì)文章示例時(shí),將一些數(shù)據(jù)處理邏輯放到數(shù)據(jù)庫(kù)中,實(shí)現(xiàn)幾個(gè) PL/SQL 存儲(chǔ)過(guò)程。在這里您學(xué)習(xí)了如何使用 Oracle XML DB 特性從網(wǎng)頁(yè)中獲取 XML 數(shù)據(jù),然后從獲取的 XML 文檔中提取所需的信息。然后,構(gòu)建一些 Python 代碼,用以編排存儲(chǔ)過(guò)程所執(zhí)行的完整操作流。依次從構(gòu)建的 PSP 頁(yè)面中調(diào)用這些 Python 代碼,以實(shí)現(xiàn)應(yīng)用程序的前端層。因此,您獲得了相應(yīng)的應(yīng)用程序,該應(yīng)用程序從網(wǎng)頁(yè)中獲取某些實(shí)時(shí)數(shù)據(jù),并跟蹤用戶在您站點(diǎn)上的活動(dòng),將該信息存儲(chǔ)在數(shù)據(jù)庫(kù)中。在 Python 端,您看到了如何使用 Python 語(yǔ)言的內(nèi)置工具獲取、保留以及操作結(jié)構(gòu)化數(shù)據(jù),這些工具包括:列表、字典和列表內(nèi)涵。您還了解了在將應(yīng)用程序邏輯和數(shù)據(jù)封裝到類中時(shí)如何利用 Python 的面向?qū)ο蟮奶匦浴?/P>
【編輯推薦】