程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle數據庫基礎 >> 用Oracle和Python武裝你的頭腦

用Oracle和Python武裝你的頭腦

編輯:Oracle數據庫基礎

PL/SQL 比較適合於 Oracle 數據庫中的編程任務。而大多數 Oracle 專業人員並不會局限於完全在數據庫中進行工作。您可能曾經遇到過許多不便於使用甚至無法使用 PL/SQL 的任務,如操作磁盤上的文件、調用外部程序或 shell 腳本、執行復雜的文本分析以及頻繁執行面向對象的工作。如果 PL/SQL 是您唯一的編程語言,那麼可能會為您的 Oracle 工作帶來很大的不便。

既然如此,應另外選擇哪種語言呢?您的時間可能並不多,因此它應該是一種簡單的語言,即易於學習和使用。某些動態語言(尤其是 Perl、Python、PHP 和 Ruby)正是因為其易用性而獲得了越來越多的關注。動態語言的許多用戶發現,他們編寫有效代碼的速度要比使用更傳統的語言(如 C++ 或 Java)快很多倍。

尤其值得一提的是 Python,該語言不但易於使用,而且還更高效,它生成的代碼不但具有可讀性而且結構良好。因此,當您再看幾個月前寫的代碼時,仍可以理解、修改並重用它。由於具備近乎自描述的外觀,因此 Python 清晰、簡潔的語法有時被稱作“可執行的偽代碼”。Python 是一種高度面向對象的語言,它易於學習並遵循良好的編程風格,即使那些沒有經過正式軟件工程培訓的用戶也可以使用它。由於易於學習,因此它無論是對於新手還是對於專家都具有很大的吸引力。

與 Perl 一樣,Python 的功能可以滿足各種軟件需要;該語言的簡單並不代表它膚淺和應用面窄。一旦您使用了 Python,您就不會再想使用第三種語言。

最後,Python 是免費的跨平台開放源代碼軟件。Python 實在值得一試!

本文並不嘗試對 Python 進行全面的介紹或細致的講解,而是創建一個有用的示例應用程序,用以演示對 Oracle 用戶最重要的 Python 功能。如果您確信 Python 值得進一步研究,那麼本文提供的鏈接可以為您提供更多信息。

快速入門

如果您正在運行 Linux,則可能已經擁有了 Python,它包含在常見的發行版本中。否則,請從 www.python.org 下載它。除了源代碼以外,還提供了便於使用的 RPM 和 Windows 可執行安裝程序。安裝後,請確保 PATH 中包含 Python 可執行文件,然後在命令提示符下鍵入 Python 啟動交互式解釋器。您將看到類似如下所示的信息:

c:\>Python

Python 2.4 (#60, Nov 30 2004, 11:49:19) [MSC v.1310 32 bigt (Intel)] on win32

Type "help", "copyright", "credits", or "license" for more information.

>>>

>>> 提示符等待接受您發出的 Python 命令。與 SQL*Plus 一樣,Python 允許您即席執行命令或在編寫成熟的腳本之前試驗命令。

按照慣例,您接下來將執行以下命令:

>>> print 'Hello, World'

解釋器做出以下響應:

Hello, World

注意不要鍵入 Print 或 PRINT。在 Python 中,所有東西(命令、變量名等)都是區分大小寫的。

使用文本文件

假設您用一個標准的 init.ora 文件來數據庫中的所有默認參數。您需要將其內容與特定數據庫實例的 init.ora 文件內容進行比較。

清單 1:init_default.ora

DB_BLOCK_SIZE=4096

COMPATIBLE=9.2.0.0.0

SGA_MAX_SIZE=104857600

SHARED_POOL_SIZE=50331648

清單 2:init_orcl.ora

FAST_START_MTTR_TARGET=300

SHARED_POOL_SIZE=50331648

DB_BLOCK_SIZE=8192

COMPATIBLE=9.2.0.0.0

UNDO_MANAGEMENT=AUTO

SGA_MAX_SIZE=135339844

首先打開要讀取的 init_orcl.ora。

>>> initFile = open('init_orcl.ora')

您現在已經打開了該文件並指定了一個變量 initFile 來引用它。(Python 使用一個 = 進行賦值,並使用 == 進行比較,而 PL/SQL 分別使用 := 和 =。)注意,您不必聲明 initFile 或指定它的數據類型;作為一種“動態類型”語言,Python 可以自動識別。

我們來看看結果如何。

>>> firstLine = initFile.readline()

>>> firstLine

'FAST_START_MTTR_TARGET=300\n'

其中的 readline 是對象 initFile 中定義的方法。如果您不熟悉面向對象的編程,則對您而言這將是一個全新的語言,而 Python 語言為您了解此概念提供了一個出色的環境。

從 PL/SQL 的使用經歷中可以知道,readline 之後不需要圓括號,這是因為您並未向它傳遞任何參數。但在 Python 中,省略圓括號將導致意外的結果。

>>> firstLine = initFile.readline

>>> firstLine

您實際上並未調用 readline 方法,而是只將一個指針指向它並將其插入到 firstLine 中。這在某些高級編程技術中可能非常有用;例如,您實際上可以從分配給該函數的位置調用該函數。

>>> firstLine()

'SHARED_POOL_SIZE=50331648\n'

但對現在而言,只需記住在調用 Python 函數時必須使用 ()。下面我們向 firstLine 中插入一個全新的字符串以繼續操作。

>>> firstLine = initFile.readline()

>>> firstLine

'DB_BLOCK_SIZE=8192\n'

自省

firstLine 結尾的 \n 是一個您並不需要的換行符。如何刪除它?盡管 Python 提供了出色的文檔,但您也不必參考它 - Python 的自省功能可以幫助您確定如何從提示符下執行正確操作。

在 Python 中,類似 firstLine 這樣的字符串是一個對象。作為對象,它包含方法,即為操作它而定義的函數。下面我們來看看可以對 firstLine 執行哪些操作。

>>> type(firstLine)

>>> dir(firstLine)

['__add__', '__class__', '__contains__', '__delattr__',

'__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__',

'__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__',

'__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__',

'__new__', '__reduce__', '__reduce_ex__',

'__repr__', '__rmod__', '__rmul__', '__setattr__',

'__str__', 'capitalize', 'center', 'count', 'decode',

'encode', 'endswith', 'expandtabs', 'find', 'index', 'isalnum',

'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper',

'join', 'ljust', 'lower', 'lstrip', 'replace', 'rfind', 'rindex',

'rjust', 'rstrip', 'split', 'splitlines', 'startswith', 'strip',

'swapcase', 'title', 'translate', 'upper', 'zfill']

能否執行 strip?根據上面顯示的內容,應該可以執行。按照約定,一個簡單的文檔字符串存儲在每個對象的 __doc__ 方法中。(類似 __doc__ 這樣的以兩個下劃線開頭和結尾的名稱保留給系統定義的特殊方法和屬性使用。)下面我們將打印 strip.__doc__,看看它是否是您所需的。

>>> print firstLine.strip.__doc__

S.strip([chars]) -> string or unicode

返回字符串 S 的一個副本,並刪除了前導空格和後綴空格。

如果給出了 chars 且非 None,則刪除 chars 中字符。

如果 chars 為 unicode,則在剝離前將把 S 轉換為 unicode

>>> firstLine = firstLine.strip()

>>> firstLine

'DB_BLOCK_SIZE=8192'

接下來,您需要對 firstLine 中的參數與其值進行區分。盡管很想展示一下 Python 強大的正則表達式處理能力,但我們還是采用了一個更簡單的方式:字符串方法 split()。

>>> firstLine.split('=')

['DB_BLOCK_SIZE', '8192']

變量和賦值

調用 split() 生成了一個由位於分隔符 = 之前和之後的字符串組成的列表。遺憾的是,由於您未將該結果指定給任何變量,因此結果只顯示到屏幕,隨後就不見了。這次,您將使用多個賦值來同時捕獲兩個結果。您可能想使用向上箭頭鍵來省去一些鍵入操作。

>>> param, val = firstLine.split('=')

>>> param

'DB_BLOCK_SIZE'

>>> val

'8192'

實際上,您將需要分別存儲多個參數的值。這種場合最適於使用一個稱作字典的強大 Python 變量類型。字典是一個無序的鍵集,即值對;實際上,它與 Oracle 數據庫中的普通(堆)表非常相似。鍵和值可以是數字、字符串或其他對象。您將創建一個空字典,並使用您到目前為止提取的信息填充它。

>>> initParams = {}

>>> initParams[param] = val

>>> initParams

{'DB_BLOCK_SIZE': '8192'}

現在,從打開的文件中提取另一行,並將該行也存儲到字典中。這次,您將把 strip() 直接連接到 readline() 的結尾,就好象您在使用一個 UNIX 管道。

>>> nextLine = initFile.readline().strip()

>>> param, val = nextLine.split('=')

>>> initParams[param] = val

>>> initParams

{'DB_BLOCK_SIZE':'8192', 'COMPATIBLE': '9.2.0.0.0'}

編寫腳本

現在,您已經以交互方式試用了解釋器,下面您將准備編寫一個 Python 腳本來處理整個文件。使用 Ctrl-D(在 Unix/Linux 中)或 Ctrl-Z(在 Windows 中)退出 Python 解釋器,然後創建一個文本文件 - 稱之為 readInitOra.py。

initFile = open('init_orcl.ora', 'r')

initParams = {}

rawTextLine = initFile.readline()

while rawTextLine:

param, val = rawTextLine.strip().split('=')

initParams[param] = val

rawTextLine = initFile.readline()

print initParams

在閱讀此代碼時,您很可能想到“命令結尾的分號哪去了?BEGIN 和 END 語句以及用於標記塊的大括號哪去了?”實際上,Python 並不使用這些符號。按照慣例,幾乎所有編程人員都使用換行符分隔命令,並使用縮進指示代碼塊,以便用戶可以閱讀代碼。同時,Python 以外的大多數語言都要求他們使用一套不同的符號與編譯器或解釋器進行通信。使用兩套符號將使代碼雜亂不堪,並將產生一個很大的風險 - 顯示給人眼的符號可能與顯示給計算機的符號不同步,從而產生另人難以理解的錯誤。而 Python 可以像用戶那樣讀取代碼,從而消除了混亂並避免出現風險。

下面我們來看看代碼操作。在操作系統提示符(而非 Python 解釋器提示符)下,鍵入

c:\> Python readInitOra.py

{'UNDO_MANAGEMENT':'AUTO', 'COMPATIBLE': '9.2.0.0.0',

'DB_BLOCK_SIZE':'8192', 'FAST_START_MTTR_TARGET' : '300',

'SGA_MAX_SIZE':157286400, 'SHARED_POOL_SIZE': '50331648'}

如果您習慣將 readInitOra.py 中的所有行縮進幾個空格,則將使 Python 混淆並產生一個語法錯誤。縮進指示代碼塊,因此在不指示代碼塊的情況下請不要進行縮進。返回並確保不在塊中的每一行都從第 1 列開始。

您實際上需要在多個位置使用此代碼,因此我們將其從簡單的腳本改進為接受參數的函數定義。

def read(fileName):

initFile = open(fileName, 'r')

initParams = {}

rawTextLine = initFile.readline()

while rawTextLine:

param, val = rawTextLine.strip().split('=')

initParams[param] = val

rawTextLine = initFile.readline()

return initParams

嵌套

下面,您需要創建一個包含 init_default.ora 中的默認參數的相似字典。您完全可以將其讀取到全新的變量,但這裡我們將介紹對象如何可靠地嵌套在 Python 中。您將創建一個簡單的父目錄 initParams,並針對每個 init.ora 文件在其中嵌套一個目錄。您還將導入剛剛編寫的文件,以便可以調用它的 read() 函數。創建一個名為 compareInitOra.py 的新文本文件。

import readInitOra

initParams = {}

# brackets denote a list that we can loop through

for fileName in ['init_orcl.ora', 'init_default.ora']:

initParams[fileName] = readInitOra.read(fileName)

print initParams

c:\> Python compareInitOra.py

{'init_orcl.ora':

{'UNDO_MANAGEMENT':'AUTO', 'COMPATIBLE': '9.2.0.0.0',

'DB_BLOCK_SIZE':'8192', 'FAST_START_MTTR_TARGET': '300',

'SGA_MAX_SIZE':'157286400, 'SHARED_POOL_SIZE': '50331648'}

'init_default.ora':

{'COMPATIBLE':'9.2.0.0.0', 'DB_BLOCK_SIZE': '4096',

'FAST_START_MTTR_TARGET':'300', 'SGA_MAX_SIZE': '100663296',

'SHARED_POOL_SIZE': '50331648'}}

這次的輸出包含一些空格,以幫助您查看嵌套結構。您可以輕松地編寫 Python 代碼以可靠地打印它,也可以使用 Python 的 pprint 模塊,但由於我們是數據庫用戶,因此將該數據置入 Oracle 數據庫中。

在 Python 中使用 SQL

要訪問數據庫,Python 解釋器需要安裝數據庫模塊。您有許多選擇,這些選擇均遵守標准化的 API 規范,並且曾經以編程方式使用過 ODBC 或 JDBC 的任何人均非常熟悉它們。您將使用 cx_Oracle,因為它比較易於安裝。只需下載一個與您的 Python 和 Oracle 數據庫版本匹配的 Windows 安裝程序。

安裝 cx_Oracle 後,返回 Python 命令行解釋器進行試用。由於 cx_Oracle 是一個獨立於核心 Python 語言的模塊,因此在將其用於任何會話或腳本之前必須導入它。

>>> import cx_Oracle

請記住要使用大寫字母!下面,我們將創建一個用於存儲結果的表。

>>> orcl = cx_Oracle.connect('scott/tiger@orcl')

>>> curs = orcl.cursor()

>>> sql = """CREATE TABLE INIT_PARAMS

... ( fileName VARCHAR2(30),

... param VARCHAR2(64),

... value VARCHAR2(512) )"""

三個引號 (""") 是一個用於輸入包含換行符的方便語法。Python 解釋器將其提示符從 >>> 更改為 ... - 提醒您將繼續從上一行開始的輸入。

>>> curs.execute(sql)

>>> curs.close()

現在您的表已經准備就緒,下面我們將編寫 recordInitOra.py 來填充它。

import readInitOra, cx_Oracle

initParams = {}

for fileName in ['init_orcl.ora', 'init_default.ora']:

initParams[fileName] = readInitOra.read(fileName)

orcl = cx_Oracle.connect('scott/tiger@orcl')

curs = orcl.cursor()

for fileName in initParams.keys():

for param in initParams[fileName].keys():

value = initParams[fileName][param]

sql = """INSERT INTO INIT_PARAMS VALUES

(:fileName, :param, :value)"""

bindVars = {'fileName':fileName,

'param':param, 'value':value}

curs.execute(sql, bindVars)

curs.close()

orcl.commit()

以上就是全部代碼了。注意,您這次在 SQL 字符串中使用了綁定變量,並在一個單獨字典中為它們提供了值。使用綁定變量可以幫助您擺脫 SPCSP(防止錯誤使用共享池協會)的麻煩。

從查詢中獲取結果略微復雜一些。對游標對象調用 execute() 後,可以使用 fetchone() 一次獲取一行,也可以使用 fetchall() 獲取所有行的列表。無論在哪種情況下,每一行均采用字節組(即可以由數值索引訪問的有序值序列)的形式。例如,我們將編寫 compareInitOra.py 來打印與 V$PARAMETER 中的當前值沖突的 init_orcl.ora 參數:

import readInitOra, cx_Oracle

def readLiveParams():

liveParams = {}

orcl = cx_Oracle.connect('scott/tiger@orcl')

curs = orcl.cursor()

curs.execute('SELECT name, value FROM V$PARAMETER')

row = curs.fetchone()

while row:

(param, val) = (row[0], row[1])

liveParams[param.upper()] = val

row = curs.fetchone()

return liveParams

liveParams = readLiveParams()

fileName = 'init_orcl.ora'

fileParams = readInitOra.read(fileName)

for (param, val) in fileParams.items():

liveVal = liveParams.get(param)

if liveVal != val:

print """For %s, V$PARAMETER shows %s,

but the file %s shows %s""" %

(param, liveVal, fileName, val)

Python 的對象關系映射工具

您可能對對象關系映射 (ORM) 工具很感興趣,這些工具可以取代 SQL 的編寫並為編程人員提供一個面向對象的界面。Oracle TopLink 便是一個適用於 Java 的對象關系映射器的例子。用於 Python 的與 Oracle 兼容的 ORM 工具有:

Modeling Object-Relational Bridge for Python

forgetSQL

ll.orasql

SQLObject(馬上或很快便將支持 Oracle)

sqlWrap.p

該腳本引入了一些您還沒見過的技巧:

對字典 fileParams 調用 items() 將返回一個(鍵, 值)對列表。可以通過在 for 語句中指定兩個循環變量來遍歷這些鍵值。

調用 liveParams.get(param) 的工作方式類似於 liveParams[param],區別在於如果在 liveParams 中未找到參數,則將返回一個錯誤 - 非常類似於“ORA-01403:no data found in PL/SQL”消息。而 liveParams.get(param) 將在 liveParams 中不存在參數的情況下返回 None。

Python 可以使用 % 運算符執行字符串替換。與 C 的 printf 相似,%s 表示將在該點插入一個字符串形式的值。這些值按順序從 % 之後的字節組中提取。

最後一行代碼比您在沒有換行符的情況下進行鍵入運行時間更長,因此您使用了一個反斜線,從而打破了 Python 將換行符解釋為命令結尾這一通常的規則。

Web 發布

最後,我們將通過 Python Web 應用程序公開此功能。首先,您需要選擇要使用的 Python Web 應用程序平台,這可能要比實際編寫應用程序困難!由於它們非常易於用 Python 編寫,因此有大量平台可供使用。最流行的平台是 Zope;Zope 應用程序可以完全從易於用戶使用的網頁中創建和管理。或者,如果您對 Ruby on Rails 很感興趣,則可能要考慮 TurboGears 或 Django - Python 自身的從上自下的應用程序構建器。TurboGears 也支持在應用程序中方便地包含 AJax。現在,我們將選擇一個非常簡單的框架 CherryPy。請在此處下載它。

首先,對 compareInitOra.py 稍加修改(如下所示),創建一個 Html() 函數,從而返回包含所需文本和標記的字符串。然後,只需要編寫七行多代碼即可將該函數公開為 Web 應用程序。

清單 3:

compareInitOra 

import readInitOra, cx_Oracle
def readLiveParams(instance):
liveParams = {}
orcl = cx_Oracle.connect('scott/tiger@' + instance)
curs = orcl.cursor()
curs.execute('SELECT name, value FROM V$PARAMETER')
row = curs.fetchone()
while row:
(param, val) = (row[0], row[1])
liveParams[param.upper()] = val
row = curs.fetchone()
return liveParams

fileName = 'init_orcl.ora'

def Html(initOraFile, instance):
result = ""
fileParams = readInitOra.read(initOraFile)
liveParams = readLiveParams(instance)
for (param, val) in fileParams.items():
liveVal = liveParams.get(param)
if liveVal == val:
result += "%s
\n" % (val) else result += "%s (file) %s (live)
\n" % (val, liveVal) return result import cherrypy class WebApp: def index(self, initOraFile='init.ora', instance='orcl'): return Html(initOraFile, instance) index.exposed = True cherrypy.root = WebApp() cherrypy.server.start()
運行該腳本時,它開始以 Web 服務器的形式(默認情況下)在端口 8080 上工作。將浏覽器指向 http://localhost:8080/?initOraFile=init_orcl 將提供您所需的 Html 頁面。

結論

衷心希望 Python 的易用性、簡潔行和可讀行能夠引起您的興趣。您對 Python 的強大功能還不了解。它的功能包括簡潔的異常處理、單元測試、面向對象、實用編程、GUI 工具包、Web 框架、XML、Web 服務 - 編程人員幾乎可以執行任何操作。隨著工作變得更高級,您不必“過渡”到其他語言。

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