0%

(译)Python Database API 规范 2.0

之前貌似说要再重新学习一下 DB API 的内容,但是拖延症发作,好不容易才看了一遍这份 PEP249 的内容,顺手又作了一下翻译(应该是继 PEP3333 以来的第二篇)。不过本人能力有限,可能还是会有一些蹩脚的地方,请谨慎食用😜。

介绍

该 API 的定义目的时为了鼓励或促进那些用于访问数据库的 Python 模块之间保持一定的相似性。我们希望通过这样做可以达到某种一致性的要求:更加容易理解各个(连接数据库)的 Python 模块、跨数据库的操作代码可以更加具有可移植性、让 Python 可以连接(并操作)更多的数据库。

这份文档描述了 Python Database API 规范的 2.0 版本以及一组通用的可选扩展标准。之前的在 PEP248 中的 1.0 版本依然可以用作参考。我们鼓励 Python 包的开发者在开发新接口的时候遵循此版本的规范。

模块接口

构造方法

规范约定通过 connection 对象来访问数据库。(数据库连接)模块必须提供为 connection 对象以下的构造方法:

connect(parameters...)

这个构造方法用于创建数据库连接。
返回一个 Connection 对象。它可以接收一组数据库所依赖的参数。

* 依赖参数

作为一份指导, Connection 对象的构造函数参数应该以关键字参数的形式实现并遵循以下参数顺序,以便使用上更加直观:

参数 含义
dsn 数据源字符串
user 用户名字符串(可选)
password 密码字符串(可选)
host 主机名(可选)
database 数据库名(可选)

例如,一个连接看上去会像这个样子:

1
connect(dsn='myhost:MYDB', user='guido', password='234$')

全局变量

模块必须定义以下全局变量:

apilevel

用于说明模块所支持的 DB API level 的字符串。
目前仅支持字符串 “1.0” 和 “2.0”。如果没有给出,则默认假设支持 DB-API 1.0 level 。

threadsafety

用于说明此模块接口所支持的线程安全级别,以整型表示。以下是可选值:

threadsafety 含义
0 线程间不可“共享”模块
1 线程间可以“共享”模块,但不可“共享”连接
2 模块以及数据库连接均可以在线程间“共享”
3 模块、数据库连接以及游标(cursors)均可以在线程间“共享”

上文中,“共享”一词在语境中的含义是:两个线程可以使用同一个 资源 ,而不用使用互斥信号量(mutex semaphore)来实现资源锁。注意,即使通过使用互斥(mutex)来管理访问权限,你也无法始终确保外部资源的线程安全 —— 这些资源可能依赖全局变量或者其他超出你控制范围的外部源。

paramstyle

用于说明模块接口所期望的参数格式化风格,以下是可选值:

paramstyle 含义
qmark 问号风格,例如 .... WHERE name=?
numeric 数字配合位置参数风格,例如 ...WHERE name=:1
named 命名参数风格,例如 ...WHERE name=:name
format ANSI C printf 代码格式化风格,例如 ...WHERE name=%s
pyformat Python 的扩展格式化风格,例如 ...WHERE name=%(name)s

模块实现者可能更倾向于使用 numericnamed 或者 pyformat,因为它们更为清晰而且灵活。

异常

模块应该要通过以下的 execption 以及其相关子类来提供全部的报错信息:

Warning

对于重要警告抛出的异常类型,例如插入数据的时候发生 data truncation 等。它必须是 Python 的 StandardError 的子类(这个类在 exceptions 模块中定义)。

Error

此异常是所以其他 error 异常的基类。通过它,你可以只写一条异常捕获语句就可以捕获全部的 error 异常。Warning 不会被视为 error ,因此不使用它作为基类。它必须是 Python 的 StandardError 的子类(这个类在 exceptions 模块中定义)。

InterfaceError

针对数据库接口而非数据库本身的错误所要抛出的异常类。它必须是 Error 的子类。

DatabaseError

针对数据库本身错误所要抛出的异常类。它必须是 Error 的子类。

DataError

由于数据处理出现问题而导致的错误所抛出的异常类,例如除以零、数值大小超出范围等。它必须是 DatabaseError 的子类。

OperationalError

针对数据库操作相关的错误(并且不一定实在程序员控制之下发生的)所要抛出的异常类,例如发生意外的连接断开、找不到数据源名称、事务无法处理、处理期间内存分配出错等。它必须是 DatabaseError 的子类。

IntegrityError

当数据库的关系完整性受到影响时所要抛出的异常类,例如外键检验失败。它必须是 DatabaseError 的子类。

InternalError

数据库发生内部错误时所要抛出的异常类,例如游标失效、事务不同步等。它必须是 DatabaseError 的子类。

ProgrammingError

针对编码过程中的错误所要抛出的异常,例如表未找到或表已存在、SQL 语句存在语法错误、指定参数的数量有误等等。它必须是 DatabaseError 的子类。

NotSupportedError

使用某些数据库不支持的方法或 API 的时候所要抛出的异常类,例如对不支持事务或已经关闭了事务的连接使用 .rollback() 方法。它必须是 DatabaseError 的子类。

以下为异常类的继承结构:

1
2
3
4
5
6
7
8
9
10
11
StandardError
|__Warning
|__Error
|__InterfaceError
|__DatabaseError
|__DataError
|__OperationalError
|__IntegrityError
|__InternalError
|__ProgrammingError
|__NotSupportedError

Connection 对象

Connection 对象必须实现以下方法。

Connection 方法

.close()

立即关闭连接(而不是每次都调用 .__del__() 方法)

使用此方法后连接将不再可用。如果试图对这个连接做任何操作都会抛出 Error (或其子类)的异常。这同样适用于这个连接的所有游标对象。注意,如果不先 commit 变更的情况下关闭连接会导致执行隐式的 rollback 操作。

.commit()

将任何挂起的事务提交到数据库。

注意,如果数据库支持自动提交功能,那么必须要先关掉它(这个方法才会起效)。你可以选择提供一个接口方法来重新打开自动提交。

对于不支持事务的数据库,其对应的模块应该以 空方法 (void functionality)的方式实现这个方法。

.rollback()

此方法是可选的,因为并非所有数据库都提供事务的支持。

如果数据库确实提供了事务的支持,则此方法会回滚数据库到任何挂起的事务之前。如果不先 commit 变更的情况下关闭连接会导致执行隐式的 rollback 操作。

.cursor()

使用此连接返回一个 Cursor 对象。

如果数据库并未直接提供游标的概念,则实现模块必须使用其他方式来模拟规范所需的“游标”。

数据库接口可以选择通过给方法提供一个字符串类型的参数来构建具名 cursor ,这个并不是标准所要求的,主要是为了兼容 .fetch*() 方法的语义考虑。

Cursor 对象

这个对象代表数据库的游标(cursor),常用于管理获取操作的上下文。同一个 connection 对象创建的 cursor 之间比并不是孤立(isolated) 的,比如说,一个 cursor 对数据库的做的任何改动都会马上被其他的 cursor 所看到。而由不同的 connection 对象中创建的 cursor 之间,它们的隔离与否,取决于是否实现了事务的支持(可以查看 Connection 对象的 .rollback() 以及 .commit() 方法)。

Cursor 属性

.description

这个只读的属性包含了以下 7 项内容组成的序列(一般是元组)的结果列描述。

每一个序列都包含一个结果列的信息描述。

  • name
  • type_code
  • display
  • internal_size
  • precision
  • scale
  • null_ok

其中,前两项是必填(name 以及 type_coe)的;其他五项为可选项,如果没有合适的、有意义的值可以提供就会被设置为 None

在操作没有返回任何行的时候,或者 cursor 还没有通过 .execute*() 方法调用过操作之前,这个值就会为 None

type_code 可以参照下面 Type Objects 一节得到解释。

.rowcount

这个只读属性负责返回 行数,在这里是指最近一次 .execute*() 操作所得到的结果行数( DQL 语句如 SELECT )或所影响的行数( DML 语句如 UPDATEINSERT )。

如果这个 cursor 还没有执行过 .execute*() 操作,或者接口无法确定最后一次操作的 rowcount,则这个属性的值为 -1 。

以后的 DB API 版本的标准会重新定义,而目前最新的表述是:该值会返回 None 而不是 -1 。

Cursor 方法

.callproc(procname[, parameters])

(这个方法是可选实现的,因为不是所有的数据库都提供存储过程功能)

调用指定 procname 作为名称的存储过程,参数序列( sequence of parameter )必须包含一个条目,由存储过程所需的每个参数组成。而调用的结果,将会在输入序列的副本上作修改,然后返回。其中,IN 参数(输入参数)保持不变, OUT 参数(输出参数)和 INOUT 参数(输入输出参数)有可能被替换为新的值。

存储过程也可以提供结果集作为输出。这样的话必须通过标准的 .fetch*() 方法来获取。

.close()

(此方法用于)马上关闭 cursor (而不是调用 __del__ 方法)

当执行这个操作开始,cursor 将无法使用。如果之后试图使用这个 cursor 执行任何操作,都会引发一个 Error 或其(子类)的异常。

.execute(operation [, parameters])

(此方法用于)准备并执行一个数据库操作(查询 query 或者命令 command )

参数可以以序列或映射表的形式提供,它们会被绑定到操作中的变量。变量是以数据库指定的表示方法所标识的(详细请参考模块的 paramstyle 属性)。

注意,对于 parameters 参数,模块会使用 __getitem__ 方法来匹配位置参数(根据数字形式)或者关键字参数(根据字符串形式)。这意味着它同时支持 parameters 以序列或者映射的形式作为输入。

cursor 负责保留(retain)操作的引用。如果再次传入相同的操作对象,那么 cursor 可以优化这个行为。这对于那种(多次)执行相同的操作但是绑定的参数不一样的情况下最为有效。

为了使得操作重用得到最大的效率,最好是使用 etinputsizes() 方法来提前指定参数的类型以及大小。参数与预定义的信息不匹配也是合法的,在实现上应该考虑做补偿(compensate),尽管可能会导致效率降低。

参数也可以指定为元组列表,例如,在单个操作中插入多行时。但这种操作并不推荐,这个时候应该使用 .executemany() 替代。

此方法未定义返回值。

.executemany(operation, seq_of_parameters)

(此方法用于)准备一个数据库操作(query 或 command),然后针对 seq_of_parameters 中找到的全部参数序列或映射表来执行。

DB 模块对于此方法,可以使用多次调用 .execute() 方法的思路来实现;或者使用 数组操作(array operation) 以使得数据库可以能在一次调用中处理整个参数序列。

如果某个数据库操作使用了这个方法来执行而产生了一个或多个结果集,将构成未定义行为;当检测到通过此操作创建了结果集时,实现方被允许(但不做要求)抛出一个异常。

.execute() 相同的注释也相应地适用于此方法。

此方法未定义返回值。

.fetchone()

(此方法用于)获取查询结果集(query result set)中的下一行。方法将返回一个序列,或者在没有更多可用数据时返回 None

如果之前调用 .execute*() 方法没有产生任何结果集,或者在此之前尚未调用任何方法,此方法将抛出 Error (或其子类)异常。

注意,数据库接口可能通过数组或者其他的优化形式来实现行数据的获取。因此无法保证对此方法的调用会使得对应 cursor 仅仅往前移动一行。

.fetchmany([size=cursor.arraysize])

(此方法用于)获取查询结果集的下一组行。方法将返回一个序列的序列(例如元组列表)。当结果集中没有更多行的时候,返回空序列。

每次调用所获取的行数由参数 size 决定。如果没有给出这个入参,则默认使用 cursor 的 arraysize 属性来确定要获取的行数。这个方法会尽力获取 size 所指示的行数;如果因为结果集可用的行已经不足,则在这种情况下方法可能会返回更少的行。

如果之前调用 .execute*() 方法没有产生任何结果集,或者在此之前尚未调用任何方法,此方法将抛出 Error (或其子类)异常。

请注意,size 参数的设置大小应该从性能的角度出发来考虑。为了获得最佳性能,通常是直接使用 .arraysize 属性的值。如果自定义了 size 入参,那么最好保持一致(即不要每次调用 fetchmany 都使用不同的 size 值)。

.fetchall()

(此方法用于)获取查询结果的所有(剩余的)行结果,将它们作为序列的序列返回(例如元组列表)。注意,cursor 的 arraysize 属性可能会影响此操作的性能。

如果之前调用 .execute*() 方法没有产生任何结果集,或者在此之前尚未调用任何方法,此方法将抛出 Error (或其子类)异常。

.nextset()

(此方法是可选的,因为并非所有数据库都支持多结果集)

这个方法会使得 cursor 跳到下一个可用的结果集,并丢弃当前结果集的所有剩余行。

如果没有更多的集合,这个方法会返回 None 。否则,它将返回一个真值,后续使用 .fetch*() 方法会返回下一个结果集的行内容。

如果之前调用 .execute*() 方法没有产生任何结果集,或者在此之前尚未调用任何方法,此方法将抛出 Error (或其子类)异常。

.arraysize

这个可读写属性指定了通过 .fetchmany() 方法一次可以获取的行数。它的值默认为 1 ,意味着一次只会获取一行数据。

实现方在实现 .fetchmany() 这个方法时必须留意这个值,但还是可以选择一次一行地和数据库进行交互。它也可以用于实现 .executemany() 方法上。

.setinputsizes(sizes)

此方法可以在调用 .execute*() 之前使用,用于预定义数据库操作参数所需的内存区域。

size 参数是一个序列 —— 其中每个 .execute*() 的输入参数对应序列的一项。该项的值应该是对应使用的输入参数的 Type Object;或者是用于指定字符串类型参数的最大长度的整数。如果该项为 None,则不会为该列保留预定义的内存区域(这对于避免给大的输入参数保留过大的内存区域相当有用)。

这个方法应该在 .execute*() 方法之前被调用。

实现方可以自由地选择是否实现这个方法,而用户也可以有不使用这个方法的自由。

.setoutputsize(size[, column])

为获取大的数据列(例如 LONG 类型、BLOB 类型等)设置一个列缓冲区大小。column 参数用于指定(该列在)结果数据集的索引位置。如果不指定 column 则默认为 cursor 中全部的大数据列设置 size 大小的缓冲区。

这个方法应该在 .execute*() 方法之前被调用。

实现方可以自由地选择是否实现这个方法,而用户也可以有不使用这个方法的自由。

类型对象 Type Object 以及其构造函数

许多数据库需要对绑定操作的输入参数指定特定的输入格式。例如,如果目标的输入列是一个 DATE 类型的列,那么它必须以特定的字符串格式来绑定到数据库。同样的的问题也存在于 Row ID 列以及一些大的二进制对象(例如 blob 列以及 RAW 列)。这对于 Python 来说就不太友好,因为 .execute*() 的参数是无类型的。当 DB 模块看到一个 Python 的字符串对象时,它不知道应该将它简单的绑定为一个 CHAR 列,还是一个 raw Binary 项,抑或是一个 DATE 类型的值。

为了解决这个问题,模块必须提供以下定义的构造函数(constructors)来创建相应的对象以保存指定类型的值。当这个对象传递给 cursor 的方法时,模块就可以检测到输入参数的正确属性并对其进行相应的绑定。

一个 cursor 对象的 description 属性返回查询结果的每一列的信息。type_code 必须等于以下定义的 Type Object 之一。Type Object 可能等于多个类型代码(例如 DATETIME 可以等于 datetime 以及 timestamp 类型列的 type code 。详情可参考下面的实现提示)。

模块将包含以下的构造函数和单例对象:

Date(year, month, day)

    此函数构造一个 date 值的对象。

Time(hour, minute, second)

    此函数构造一个 time 值的对象。

Timestamp(year, month, day, hour, minute, second)

    此函数构造一个 timestamp 值的对象。

DateFromTicks(ticks)

    此函数根据给定的 ticks 值构造一个 date 值的对象。其中 ticks 是秒数,详情可参考 Python 标准库的 time 模块的描述。

TimeFromTicks(ticks)

    此函数根据给定的 ticks 值构造一个 time 值的对象。其中 ticks 是秒数,详情可参考 Python 标准库的 time 模块的描述。

TimestampFromTicks(ticks)

    此函数根据给定的 ticks 值构造一个 timestamp 值的对象。其中 ticks 是秒数,详情可参考 Python 标准库的 time 模块的描述。

Binary(string)

    此函数构造一个足以表示二进制(或 long)类型的字符串值的对象。

STRING type

    此类型对象用于描述数据库中类字符串类型的列(例如 CHAR

BINARY type

    此类型对象用于描述数据库中的大对象列(例如 LONGRAWBLOBS

NUMBER type

This type object is used to describe numeric columns in a database.
    此类型对象用于描述数据库中的数值类型的列

DATETIME type

    此类型对象用于描述数据库中 date/time 类型的列

ROWID type

    此类型对象用于描述数据库中的 Row ID 类型的列

在输入输出中,SQL 的 NULL 值在 Python 中以 None 单例对象的形式表示。

注意,使用 Unix 的 ticks 可能会导致麻烦,因为它们只支持有限的日期范围。

模块作者的实现建议

译者:主要我是一个使用者,这部分就没有翻译了,有兴趣的可以自行参阅 😀。

可选的 DB API 扩展

自 DB API 2.0 标准发布以来,模块的作者们经常会再 DB API 标准的要求之外扩展它们的实现。出于提高兼容性以及对于未来可能的标准有清晰的升级路径可言,这一节也为 DB API 2.0 标准定义了一组常见的扩展。

作为 DB API 的可选功能,数据库模块的作者可以自由地选择是否要实现这些额外的功能以及方法,或者仅在运行时抛出 NotSupportedError 以便检查其可用性。

我们建议,模块作者们通过给出 Python 的 warnings 来让编程人员有选择性地使用这些扩展。为了使得这些扩展功能可以被使用上,必须标准化这些警告消息以便(编程人员)可以屏蔽掉它们。这些所谓“标准的消息”是指以下的 Warning Message

Cursor.rownumber

此只读属性应该要提供 cursor 中的结果集从 0 开始的索引;如果无法确定其索引大小,返回 None

这个索引值可以看作 cursor 在序列(结果集)中的索引。对应的获取(fetch next)操作会根据序列中的 .rownumber 作为索引来获取对应的行数据。

Warning Message: “DB-API extension cursor.rownumber used”

Connection.Error, Connection.ProgrammingError, etc.

所有由 DB API 标准定义的异常类都必须作为 Connection 对象的属性对外公开(在模块作用域可用的除外)。

这个属性简化了在多连接环境中的错误处理。

Warning Message: “DB-API extension connection.[exception] used”

Cursor.connection

这个只读属性返回创建该 cursor 的 connection 对象的引用。

这个属性简化了在多连接环境中编写多态代码的过程。

Warning Message: “DB-API extension cursor.connection used”

Cursor.scroll(value[, mode='relative'])

根据 mode 将结果集中的 cursor 滚动到新的位置。

如果 moderelative(默认值),则将 value 作为结果集中当前位置的偏移量;如果是 absolute,则 value 代表目标的绝对位置。

如果滚动操作会导致 cursor 离开结果集,模块应该抛出一个 IndexError 异常。在这种情况下,cursor 的位置应该是未定义(undefined) —— 最理想的情况当然是完全不移动光标。

Warning Message: “DB-API extension cursor.scroll() used”

Cursor.messages

这是一个 Python 的 list 对象,负责将元组(异常类,异常值)附加到由游标从底层数据库接收的所有消息上。

除了 .fetch*() 方法之外,这个 list 的内容会自动被所有标准的 cursor 对象方法调用所清除(在方法被调用前),目的是为了避免过多的内存消耗。同样你也可以调用 del cursor.messages[:] 的方式手动清除。

数据库生成的所有错误和警告信息都放在此列表中,因此用户可以通过检查这个 list 的内容来验证调用方法的操作是否正确。

这个属性的目的是为了避免那些会导致问题的异常告警(一些告警确实只含有信息)。

Warning Mesage: “DB-API extension cursor.messages used”

Connection.messages

Cursor.messages 类似,不过 list 中的信息是面向 connection 对象的。

这个 list 对象会在任何 connection 对象方法所清空(在方法被调用前),以避免过多的内存消耗。同样你可以执行 del connection.messages[:] 来手动清除。

Warning Message: “DB-API extension connection.messages used”

Cursor.next()

.fetchone() 有着相同的语义,都是从当前执行的 SQL 语句中返回下一行数据。当结果集遍历结束时,对于 Python2.2 以上的版本应该抛出 StopIteration 异常。之前的版本由于没有 StopIteration 异常,所以取而代之应该抛出 IndexError 异常。

Warning Message: “DB-API extension cursor.next() used”

Cursor.__iter__()

这个方法返回 cursor 本身,主要是为了兼容生成器协议。

Warning Mesage: “DB-API extension cursor.__iter__() used”

Cursor.lastrowid

这个只读属性提供了最近一次被修改的行的 rowid (大多数数据库支持尽在执行单个 INSERT 操作时返回一个 rowid)。如果操作未设置 rowid 或者数据库不支持 rowid ,则此属性应设置为 None

如果最近一次的执行语句修改了多行数据,.lastrowid 的语义无法定义,例如,用 .executemany() 执行 INSERT 操作。

Warning Message: “DB-API extension cursor.lastrowid used”

可选的错误处理扩展

核心的 DB API 标准仅仅声明了一组会抛出给使用者来报告错误的异常。在某些情况下,异常可能会对程序的流程造成极大的破坏,甚至于无法执行。

对于这种情况,为了简化对于数据库错误的处理,数据库模块的作者可能会提供这样的实现,让用户自定义的错误处理程序。本节将介绍定义这些错误处理程序的标准方法。

Connection.errorhandler, Cursor.errorhandler

该可读写属性表示错误处理程序,用于处理遇到的错误情况。

这个 handler 必须是 Python 的可调用对象(callable),它包含以下参数

1
errorhandler(connection, cursor, errorclass, errorvalue)

其中:

  • connection 表示 cursor 操作的 connection 对象;
  • cursor 表示 cursor 对象(如果这个 error 不是由 cursor 引起的则为 None
  • errorclass 是表示的是错误类型,它将使用 errorvalue 作为构造参数实例化一个 error 对象。

这个标准的错误处理程序会添加错误信息倒 .messages 属性上( Connection.messages 或者 Cursor.messages ),然后抛出由指定的 errorclasserrorvalue 作为参数的异常。

如果 .errorhandler 没有被设置(即该属性为 None),那么会调用外层的标准错误处理程序。

Warning Mesasge: “DB-API extension .errorhandler used”

可选的二阶段提交(2PC/TPC)扩展

很多数据库提供了 二阶段提交 (two-phase commit) 以支持跨多个数据库链接来管理事务以及其他资源。

如果数据库后端本身提供了对 TPC 的支持而模块的作者同样希望暴露给使用者,以下的 API 就应该实现。同样,只能在运行时检查 NotSupportedError 异常判断数据库后端是否提供了 TPC 支持。

TPC Transaction IDs

大多数数据库遵循 XA 标准,transaction IDs 必须由以下三个组件组成

  • format ID
  • global transaction ID
  • branch qualifier(分支限定符)

对于特定的全局事务,前两个组件对于所有资源来说应该都是相同的,然后为全局事务的每个资源分配不同的 branch qualifier 。

各组件必须满足以下标准:

  • format ID —— 32 位的非负整数
  • global transaction ID & branch qualifier: 不超过 64 字符的字节字符串(byte string)

Transaction ID 必须由 Connection 对象的 .xid() 方法创建:

.xid(format_id, globa_transaction_id, branch_qualifier)

返回一个 transaction ID 对象,该对象用于传递给 connection 的 .tpc_*() 方法。

如果数据库连接不支持 TPC ,应该抛出 NotSupportedError 异常。

.xid() 方法返回的对象类型在此并没有定义,但是他必须提供类似序列的行为,并且允许访问三个组件。符合要求的数据库模块可以选择用元组而不是自定义一个对象来实现这个返回值。

TPC Connection 方法

.tpc_begin(xid)

使用指定的 transaction ID 来开始一个 TPC 事务。

这个方法应该在事务之外的地方被调用(例如,在 .commit().rollback() 方法被调用之后)。

此外,在 TPC 事务中调用 .commit().rollback() 会导致错误,抛出一个 ProgrammingError 异常。

如果数据库连接不支持 TPC ,应该抛出 NotSupportedError 异常。

.tpc_prepare()

此方法用于在 .tpc_begin() 之后执行第一段的事务。如果这个方法在 TPC 事务外被调用会引发一个 ProgrammingError 异常。

调用 .tpc_prepare() 之后,直到调用 .tpc_commit().tpc_rollback() 之前不能执行任何语句。

.tpc_commit([xid])

当无参调用这个方法时,会把之前由 .tpc_prepare() 负责准备阶段的事务进行提交。

如果 .tpc_commit() 先于 .tpc_prepare() 被调用,那么它就只执行单一阶段的提交。如果只有一个资源参与到全局事务中,那么事务管理器可以选择执行此操作。

当带着 xid 参数调用此方法,数据库会提交指定的事务。如果提供的是无效的 transaction ID,会抛出一个 Programming Error 异常。此时应该在事务外被调用,主要用于恢复操作。

当这个方法返回时,表示 TPC 事务的结束。

.tpc_rollback([xid])

当无参调用这个方法时,会回滚一个 TPC 事务。此方法应该在 .tpc_prepare 之前或之后调用。

当带着 xid 参数调用此方法,它会回滚指定的事务。如果提供的是无效的 transaction ID,会抛出一个 Programming Error 异常。此时应该在事务外被调用,主要用于恢复操作。

当这个方法返回时,表示 TPC 事务的结束。

.tpc_recover()

返回一个由挂起的 transaction ID 组成的 list ,它们适用于 .tpc_commit(xid).tpc_rollback(xid) 操作。

如果数据库不支持事务恢复,那么应该返回一个空列表或者直接抛出 NotSupportedError 异常。

常见问答

在数据库的 SIG 中经常会看到重复出现的对于 DB API 标准的问题。本节介绍了一些人们常对这份标准提出的问题。

问:我怎么从 .fetch*() 返回的元组来构成一个字典?

答:有几种现成的工具可以帮你完成这项工作。它们中的大多数是使用 cursor.description 属性中定义的列名作为字典键值的基本方法。

对于为什么不直接扩展 DB API 标准以支持字典返回值是有理由的。因为这样做有几个缺点:

  • 某些数据库对列名的大小写不敏感,或者会自动将列名全部转为小写或大写
  • 结果集中的列是由查询(例如使用 SQL 函数)产生的,它不一定匹配数据库表的列名,而数据库通常会用一种数据库特有的方式去生成这些列名。

因此,通过字典的键值来访问列名以及编写可移植的代码是不可能的。