目录



>>> from helper import info; info()
页面更新时间: 2020-07-05 19:24:05
操作系统/OS: Linux-4.19.0-9-amd64-x86_64-with-debian-10.4 ;Python: 3.7.3

Python 数据库 API

前面说过,有各种SQL数据库可供选择,其中很多都有相应的Python客户端模块(有些数据库甚至有多个)。 所有数据库的大多数基本功能都相同,因此从理论上说,对于使用其中一种数 据库的程序,很容易对其进行修改以使用另一种数据库。 问题是即便不同模块提供的功能大致相 同,它们的接口(API)也是不同的。 为解决Python数据库模块存在的这种问题,人们一致同意开发一个标准数据库API(DB API)。 这个API的最新版本(2.0)是在PEP 249(Python Database API Specification v2.0)中定义的, 网址为 http://python.org/peps/pep-0249.html

本节概述有关该API的基础知识。这里不会涉及其可选部分,因为它们并不适用于所有数据 库。有关该API的详细信息,可参阅前面提到的PEP,也可参阅Python官方维基百科中的数据库编 程指南( http://wiki.python.org/moin/DatabaseProgramming )。如果你对这个API的细节不感兴趣, 可跳过本节。

全局变量

所有与DB API2.0兼容的数据库模块都必须包含三个全局变量,它们描述了模块的特征。这 样做的原因是,这个API设计得很灵活,无需进行太多包装就能配合多种不同的底层机制使用。 如果要让程序能够使用多种不同的数据库,可能会比较麻烦,因为需要考虑众多不同的可能性。 在很多情况下,一种更现实的做法是检查这些变量,看看给定的模块是否是程序能够接受的。如 果不是,就显示合适的错误消息并退出或者引发异常。表13-1总结了这些全局变量。

Python DB API的模块属性

变 量 名

描 述

apilevel

使用的Python DB API版本

threadsafety

模块的线程安全程度如何

paramstyle

在SQL查询中使用哪种参数风格

API级别(apilevel)是一个字符串常量,指出了使用的API版本。DB API 2.0指出,这个变 量的值为’1.0’或’2.0’。如果没有这个变量,就说明模块不与DB API 2.0兼容,应假定使用的是 DB API 1.0。编写代码时,允许这个变量为其他值也没有害处,因为说不定什么时候DB API 3.0 就出来了。

线程安全程度(threadsafety)是一个0~3(含)的整数。0表示线程不能共享模块,而3表 示模块是绝对线程安全的。1表示线程可共享模块本身,但不能共享连接(参见13.1.3节),而2 表示线程可共享模块和连接,但不能共享游标。如果你不使用线程(在大多数情况下可能不会是这样的),就根本不用关心这个变量。

参数风格(paramstyle)表示当你执行多个类似的数据库查询时,如何在SQL查询中插入参数。’format’表示标准字符串格式设置方式(使用基本的格式编码),如在要插入参数的地方插 入%s。’pyformat’表示扩展的格式编码,即旧式字典插入使用的格式编码,如%(foo)s。除这些 Python风格外,还有三种指定待插入字段的方式:’qmark’表示使用问号,’numeric’表示使用:1 和:2这样的形式表示字段(其中的数字是参数的编号),而’named’表示使用:foobar这样的形式表示字段(其中foobar为参数名)。如果你觉得参数样式令人迷惑,也不用担心。编写简单程序时, 不会用到它们。如果需要明白特定的数据库是如何处理参数的,可参阅相关的文档。

异常

DB API定义了多种异常,让你能够细致地处理错误。然而,这些异常构成了一个层次结构, 因此使用一个except块就可捕获多种异常。当然,如果你觉得一切都正常运行,且不介意出现不 太可能出现的错误时关闭程序,可以根本不考虑这些异常。

表13-2说明了这个异常层次结构。异常应该在整个数据库模块中都可用。有关这些异常的深 入描述,请参阅DB API规范(前面提到的PEP)。

表13-2 Python DB API指定的异常

异 常

超 类

描 述

tandardError

所有异常的超类

arning

StandardError

发生非致命问题时引发

rror

StandardError

所有错误条件的超类

nterfaceError

Error

与接口(而不是数据库)相关的错误

atabaseError

Error

与数据库相关的错误的超类

ataError

DatabaseError

与数据相关的问题,如值不在合法的范围内

perationalError

DatabaseError

数据库操作内部的错误

ntegrityError

DatabaseError

关系完整性遭到破坏,如键未通过检查

nternalError

DatabaseError

数据库内部的错误,如游标无效

rogrammingError

DatabaseError

用户编程错误,如未找到数据库表

otSupportedError

DatabaseError

请求不支持的功能如回滚

连接和游标

要使用底层的数据库系统,必须先连接到它,为此可使用名称贴切的函数connect。这个函 数接受多个参数,具体是哪些取决于要使用的数据库。作为指南,DB API定义了表13-3所示的参 数。推荐将这些参数定义为关键字参数,并按表13-3所示的顺序排列。这些参数都应该是字符串。

表13-3 函数connect的常用参数

参数名

描述

是否可选

dsn

数据源名称,具体含义随数据库而异

user

用户名

password

用户密码

host

主机名

database

数据库名称

13.2.1节和第26章提供了函数connect的具体使用示例。 函数connect返回一个连接对象,表示当前到数据库的会话。连接对象支持表13-4所示的方法。

表13-4 连接对象的方法

方法名

描述

close()

关闭连接对象。之后,连接对象及其游标将不可用

commit()

提交未提交的事务——如果支持的话;否则什么都不做

rollback()

回滚未提交的事务(可能不可用)

cursor()

返回连接的游标对象

方法 rollback 可能不可用,因为并非所有的数据库都支持事务(事务其实就是一系列操作)。 可用时,这个方法撤销所有未提交的事务。

方法 commit 总是可用的,但如果数据库不支持事务,这个方法就什么都不做。关闭连接时, 如果还有未提交的事务,将隐式地回滚它们——但仅当数据库支持回滚时才如此!如果你不想依 赖于这一点,应在关闭连接前提交。只要提交了所有的事务,就无需操心关闭连接的事情,因为 作为垃圾被收集时,连接会自动关闭。然而,为安全起见,还是调用 close 吧,因为这样做不需 要长时间敲击键盘。

说到方法 cursor ,就必须说说另一个主题:游标对象。你使用游标来执行SQL查询和查看结 果。游标支持的方法比连接多,在程序中的地位也可能重要得多。表13-5概述了游标的方法,而 表13-6概述了游标的属性。

表13-5 游标对象的方法

名称

描述

callproc(name[, params])

使用指定的参数调用指定的数据库过程(可选)

close()

关闭游标。关闭后游标不可用

execute(oper[, params])

执行一个SQL操作——可能指定参数

executemany(oper, pseq)

执行指定的SQL操作多次,每次都序列中的一组参数

fetchone()

以序列的方式取回查询结果中的下一行;如果没有更多的行,就返回None

fetchmany([size])

取回查询结果中的多行,其中参数size的值默认为arraysize

fetchall()

以序列的序列的方式取回余下的所有行

nextset()

跳到下一个结果集,这个方法是可选的

setinputsizes(sizes)

用于为参数预定义内存区域

setoutputsize(size[, col])

为取回大量数据而设置缓冲区长度

表13-6 游标对象的属性

名 称

描 述

description

由结果列描述组成的序列(只读)

rowcount

结果包含的行数(只读)

arraysize

fetchmany返回的行数,默认为1

有些方法将在本章后面详细讨论,还有一些(如setinputsizes和setoutputsizes)则不会讨论。有关这些方法的详细信息,请参阅前面提到的PEP。

类型

对于插入到某些类型的列中的值,底层SQL数据库可能要求它们满足一定的条件。为了能够 与底层SQL数据库正确地互操作,DB API定义了一些构造函数和常量(单例),用于提供特殊的 类型和值。例如,要在数据库中添加日期,应使用相应数据库连接模块中的构造函数Date来创建 它,这让连接模块能够在幕后执行必要的转换。每个模块都必须实现表13-7所示的构造函数和特 殊值。有些模块可能没有完全遵守这一点。例如,接下来将讨论的模块sqlite3就没有导出表13-7 中特殊值(从STRING到ROWID)。

表13-7 DB API构造函数和特殊值

名称

描述

Date(year, month, day)

创建包含日期值的对象

Time(hour, minute, second)

创建包含时间值的对象

Timestamp(y, mon, d, h, min, s)

创建包含时间戳的对象

DateFromTicks(ticks)

根据从新纪元开始过去的秒数创建包含日期值的对象

TimeFromTicks(ticks)

根据从新纪元开始过去的秒数创建包含时间值的对象

imestampFromTicks(ticks)

根据从新纪元开始过去的秒数创建包含时间戳的对象

Binary(string)

创建包含二进制字符串值的对象

STRING

描述基于字符串的列(如CHAR)

BINARY

描述二进制列(如LONG或RAW)

NUMBER

描述数字列

DATETIME

描述日期/时间列

ROWID

描述行ID列