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 值得进一步研究,那么本文提供的链接可以为您提供更多信息。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 中,所有东西(命令、变量名等)都是区分大小写的。
清单 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'
>>> type(firstLine)能否执行 strip?根据上面显示的内容,应该可以执行。按照约定,一个简单的文档字符串存储在每个对象的 __doc__ 方法中。(类似 __doc__ 这样的以两个下划线开头和结尾的名称保留给系统定义的特殊方法和属性使用。)下面我们将打印 strip.__doc__,看看它是否是您所需的。>>> 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']
>>> 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']
>>> 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'}
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
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 数据库中。
>>> import cx_Oracle请记住要使用大写字母!下面,我们将创建一个用于存储结果的表。
>>> rcl = 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)
rcl = 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 = {}
rcl = 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 工具有:
|
清单 3: compareInitOra
import readInitOra, cx_Oracle
def readLiveParams(instance):
liveParams = {}
rcl = 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 服务 - 编程人员几乎可以执行任何操作。随着工作变得更高级,您不必“过渡”到其他语言。
http://www.oracle.com/technology/global/cn/pub/articles/devlin-python-oracle.html
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/1384/viewspace-432927/ ,如需转载,请注明出处,否则将追究法律责任。