〇、使用数据库驻留连接池

数据库驻留连接池是 Oracle Database 11g 的一个新特性。它对 Web 应用程序常用的短期脚本非常有用。它允许随着 Web 站点吞吐量的增长对连接数量进行扩充。它还支持多台计算机上的多个 Apache 进程共享一个小规模的数据库服务器进程池。没有 DRCP,Python 连接必须启动和终止一个服务器进程。

所有脚本都可使用来自服务器池的数据库服务器,不再需要时将退回服务器。

一、Oracle 简单查询

查询的基础始终是相同的:

1. 分析要执行的语句。

2. 绑定数据值(可选)。

3. 执行语句。

4. 从数据库中获取结果。importcx_Oracle

con=cx_Oracle.connect('pythonhol/welcome@127.0.0.1/orcl')

cur=con.cursor()#cursor() 方法打开语句要使用的游标。

cur.execute('select * from departments order by department_id') #execute() 方法分析并执行语句。

for result in cur:  #循环从游标获取每一行并输出该行。

print result

cur.close()

con.close()

二、Oracle 获取数据

从 Oracle 数据库中获取数据的方式有多种

1)使用cursor.fetchone()方法importcx_Oracle

con=cx_Oracle.connect('pythonhol/welcome@127.0.01/orcl')

cur=con.cursor()

cur.execute('select * from departments order by department_id')

row=cur.fetchone()# fetchone() 方法只返回一行作为一个字节组

print row

row = cur.fetchone()  # 多次调用该方法后,返回连续的多行

print row

cur.close()

con.close()

执行完毕后,两次 fetchone() 调用输出两条记录

2)使用cursor.fetchmany()方法importcx_Oracle

con=cx_Oracle.connect('pythonhol/welcome@127.0.0.1/orcl')

cur=con.cursor()

cur.execute('select * from departments order by department_id')

res=cur.fetchmany(numRows=3)#返回一个字节组列表,numRows 参数指定应返回三行

print res

cur.close()

con.close()

执行完毕后,以字节组列表形式返回了表的头三行

3)使用cursor.fetchall()方法importcx_Oracle

con=cx_Oracle.connect('pythonhol/welcome@127.0.0.1/orcl')

cur=con.cursor()

cur.execute('select * from departments order by department_id')

res=cur.fetchall()#返回所有行

print res             #输出是一个字节组列表,每个字节组包含一行的数据

forrinres:#每个字节组分别输出,选择使用哪种获取方法主要取决于您希望如何处理返回的数据

print r

cur.close()

con.close()

三、提高查询性能

通过增加每批从 Oracle 返回到 Python 程序的行数来提高查询性能的方法。importtime

import cx_Oracle

con=cx_Oracle.connect('pythonhol/welcome@127.0.0.1/orcl')

start=time.time()

cur=con.cursor()

cur.arraysize=100#每次从数据库向 Python 的缓存返回 100 条记录

cur.execute('select * from bigtab')

res = cur.fetchall()

# print res  # uncomment to display the query results

elapsed = (time.time() - start)

print elapsed, " seconds"

cur.close()

con.close()

cursor.arraysize 合理设置,可以减少对数据库的“往返”次数,通常还会降低网络负载并减少数据库服务器上下文切换次数

从数据库请求更多的数据之前,fetchone()、fetchmany()、甚至 fetchall() 方法都将从缓存读取数据。

要增加 arraysize,需要在时间/空间方面进行权衡。arraysizes 越大,Python 中用于缓存记录需要的内存也越大。

四、使用绑定变量

绑定变量允许您使用新值重新执行语句,避免了重新分析语句的开销。绑定变量提高了代码可重用性,降低了 SQL 注入攻击的风险。importcx_Oracle

con=cx_Oracle.connect('pythonhol/welcome@127.0.0.1/orcl')

cur=con.cursor()

cur.prepare('select * from departments where department_id = :id')#绑定变量前的准备

cur.execute(None, {'id': 210})  #第一次绑定变量执行,通过 python 字典的方式进行传参

res = cur.fetchall()

print res

cur.execute(None, {'id': 110})  #第二次绑定变量执行

res = cur.fetchall()

print res

cur.close()

con.close()

该语句包含一个绑定变量“:id”。该语句只准备了一次,但针对 WHERE 子句的不同值执行了两次。

因为 prepare() 方法已经对该语句进行了设置,因此对 execute() 使用特殊符号“None”代替该语句的文本参数。

cx_Oracle 驱动程序支持 INSERT 语句的数组绑定,这样可以大大提高单行插入的性能。importcx_Oracle

con=cx_Oracle.connect('pythonhol/welcome@127.0.0.1/orcl')

rows=[(1,"First"),

(2,"Second"),

(3,"Third"),

(4,"Fourth"),

(5,"Fifth"),

(6,"Sixth"),

(7,"Seventh")]

cur=con.cursor()

cur.bindarraysize=7# bindarraysize 设置为 7,意味着一次就插入全部七行

cur.setinputsizes(int, 20)  # setinputsizes() 调用描述了列的情况,第一列是整数。第二列最多为 20 个字节

cur.executemany("insert into mytab(id, data) values (:1, :2)", rows)  #调用插入全部七行。

#con.commit()               #commit() 调用被注释掉了,因此不会真正被插入数据库中

# Now query the results back

cur2 = con.cursor()         #当执行第二次查询的时候,新建了一个游标

cur2.execute('select * from mytab')

res = cur2.fetchall()

print res

cur.close()

cur2.close()

con.close()

五、创建事务

在 Oracle 数据库中操作数据(插入、更新或删除数据)时,更改的数据或新数据在提交至数据库前仅在数据库会话中可用。更改的数据提交至数据库,然后可供其他用户和会话使用。这是一个数据库事务。importcx_Oracle

con=cx_Oracle.connect('pythonhol/welcome@127.0.0.1/orcl')

rows=[(1,"First"),

(2,"Second"),

(3,"Third"),

(4,"Fourth"),

(5,"Fifth"),

(6,"Sixth"),

(7,"Seventh")]

cur=con.cursor()

cur.bindarraysize=7

cur.setinputsizes(int,20)

cur.executemany("insert into mytab(id, data) values (:1, :2)",rows)

con.commit()#commit() 是针对连接执行,而非针对游标,因此前面使用的是数据库连接的对象

# Now query the results back

cur2 = con.cursor()

cur2.execute('select * from mytab')

res = cur2.fetchall()

print res

cur.close()

cur2.close()

con.close()

如果需要在脚本中启动回滚,则可使用 con.rollback() 方法。

六、使用 PL/SQL 存储函数和过程

PL/SQL 是 Oracle 对 SQL 的过程语言扩展。PL/SQL 过程和函数在数据库中存储和运行。使用 PL/SQL 允许所有数据库应用程序重用逻辑,无论应用程序以何种方式访问数据库。许多与数据相关的操作在 PL/SQL 中的执行速度比将数据提取到一个程序中(例如,Python)然后再进行处理的速度快。Oracle 还支持 Java 存储过程。importcx_Oracle

con=cx_Oracle.connect('pythonhol/welcome@127.0.0.1/orcl')

cur=con.cursor()

res=cur.callfunc('myfunc',cx_Oracle.NUMBER,('abc',2))

printres

cur.close()

con.close()

该脚本使用 callfunc() 执行此函数。常量 cx_oracle.NUMBER 指示返回值是数字。PL/SQL 函数的两个参数作为一个字节组传输并绑定到该函数的参数。

要调用 PL/SQL 过程,使用 cur.callproc() 方法。

七、连续查询通知

连续查询通知(也称为数据库更改通知)允许应用程序在表更改时(例如,向表中插入行)接收通知。在许多情况下这一功能非常有用,包括中间层缓存无效的情况。缓存可能会容纳一些与表数据有依赖关系的值。如果表发生更改,缓存的值也必须按照新信息进行更新。