事务是数据库中处理的逻辑单元,每个事务中包括一个或多个数据库操作,既可以是读操作,也可以是写操作。
ACID 是一个“真正”事务所需要具备的一组属性集合,指的是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
原子性指的是,事务中的所有操作要么都被应用,要么都不被应用。
一致性指的是,如果数据库在执行事务之前是一致性状态,那么在事务执行之后,无论事务是否成功,数据库也应该是一致性状态。
隔离性指的是,即使数据库中有多个事务并发地执行,各个事务之间也不会互相影响,并且在并发状态下执行的事务和串行执行的事务产生的结果完全相同。
持久性指的是,在事务成功提交了之后,事务所变更的数据一定会保存起来,而不会因为任何故障导致数据丢失。
当数据库满足所有这些属性,并且只有成功的事务才会被处理时,它就被称为是符合 ACID 的数据库。
MongoDB 提供了两种 API 来使用事务:
start_transaction
和 commit_transaction
)核心 API 不为大多数错误提供重试逻辑,它要求开发人员为操作、事务提交函数以及所需的任何重试和错误逻辑手动编写代码。
与核心 API 不同,回调 API 提供了一个单独的函数,该函数封装了大量功能,包括启动与指定逻辑会话关联的事务、执行作为回调函数提供的函数以及提交事务(或在出现错误时中止)。此函数还包含了处理提交错误的重试逻辑。
在 MongoDB 4.2 中添加回调 API 是为了简化使用事务的应用程序开发,也便于添加处理事务错误的应用程序重试逻辑。
核心 API | 回调 API |
---|---|
需要显式调用才能启动和提交事务 | 启动事务、执行指定的操作,然后提交(或在发生错误时终止) |
不包含 TransientTransactionError 和 UnknownTransactionCommitResult 的错误处理逻辑,而是提供了为这些错误进行自定义处理的灵活性 |
自动为 TransientTransactionError 和 UnknownTransactionCommitResult 提供错误处理逻辑 |
要求为特定事务将显式的逻辑会话传递给 API | 要求为特定事务将显式的逻辑会话传递给 API |
在一个 Python 的例子当中,使用核心 API 的伪代码如下展示:
from pymongo import MongoClient |
|
from pymongo.errors import ConnectionFailure, OperationFailure |
|
# 显式开启一个事务会话 |
|
with client.start_session() as session: |
|
while True: |
|
try: |
|
with session.start_transaction(): |
|
# 执行事务中的多个写操作 |
|
pass |
|
# 提交事务 |
|
session.commit_transaction() |
|
except (ConnectionFailure, OperationFailure) as e: |
|
# 错误处理 |
|
if e.has_error_label("UnknownTransactionCommitResult"): |
|
# 出现暂时性错误,则重试整个事务 |
|
continue |
|
else: |
|
raise |
使用核心 API 需要注意错误的捕捉和处理,而回调 API 就不需要注意这些,其伪代码如下展示:
from pymongo import MongoClient |
|
def session_callback(session): |
|
# 执行事务中的多个写操作 |
|
pass |
|
# 显式开启一个事务会话 |
|
with client.start_session() as session: |
|
session.with_transaction(session_callback) |
在使用事务时,有几个重要的参数需要注意。可以对它们进行调整,以确保应用程序能够最佳地使用事务。
在 MongoDB 事务中有两类主要的限制:
事务的默认最大运行时间是 1 分钟。
可以通过在 mongod 实例级别上修改 transactionLifetimeLimitSeconds
的限制来增加。对于分片集群,必须在所有分片副本集成员上设置该参数。超过此时间后,事务将被视为已过期,并由定期运行的清理进程中止。清理进程每 60 秒或每 transactionLifetimeLimitSeconds/2
运行一次,以较小的值为准。
要显式设置事务的时间限制,建议在提交事务时指定 maxTimeMS
参数。实际上会使用 maxTimeMS
和 transactionLifetimeLimitSeconds
中的更小值。
事务等待获取其操作所需锁的默认最大时间是 5 毫秒。可以通过修改由 maxTransactionLockRequestTimeoutMillis
参数控制的限制来增加。如果事务在此期间无法获得锁,则该事务会被中止。
当 maxTransactionLockRequestTimeoutMillis
设置为 0
时,意味着如果事务无法立即获得所需的所有锁,则该事务会被中止。设置为 -1
将使用由 maxTimeMS
参数所指定的特定于操作的超时时间。
MongoDB 会创建出与事务中写操作数量相同的 oplog 条目。
但是,每个 oplog 条目必须在 16MB 的 BSON 文档大小限制之内。