Callback API 与 Core API
启动事务,执行指定操作并提交(或在出错时中止)。
自动包含
TransientTransactionError和UnknownTransactionCommitResult. 的错误处理逻辑。
需要显式调用以启动并提交事务。
不包含对
TransientTransactionError和UnknownTransactionCommitResult的错误处理逻辑,而是提供对这些错误进行自定义错误处理的灵活性。
回调 API
回调 API 包含以下逻辑:
在事务遇到
TransientTransactionError错误时将事务作为一个整体进行重试。如果提交操作遇到
UnknownTransactionCommitResult错误,则重试提交操作。
从 MongoDB 6.2 开始,服务器在收到 TransactionTooLargeForCache 错误时不会重试事务。
例子
Core API
核心事务 API 不包含标记为以下错误的重试逻辑:
TransientTransactionError。如果事务中的操作返回标记为TransientTransactionError的错误,则可以将事务作为一个整体进行重试。要处理
TransientTransactionError,应用程序应显式包含该错误的重试逻辑。UnknownTransactionCommitResult。如果提交返回标记为UnknownTransactionCommitResult的错误,则可以重试提交。要处理
UnknownTransactionCommitResult,应用程序应显式包含该错误的重试逻辑。
例子
以下示例包含在出现暂时性错误时重试事务的逻辑,以及在出现未知提交错误时重试提交的逻辑:
驱动程序版本
事务错误处理
无论是何种数据库系统,无论是 MongoDB 还是关系型数据库,应用程序都应采取相应措施来处理事务提交期间的错误,并包含事务的重试逻辑。
TransientTransactionError
ACID 事务中的各个写入操作不可重试,无论retryWrites 的值如何。如果操作遇到与标签"TransientTransactionError" 相关的错误,例如当主节点 (primary node in the replica set)节点降级时,则可以重试整个ACID 事务。
回调 API 包含
"TransientTransactionError"的重试逻辑。核心事务 API 不包含
"TransientTransactionError"的重试逻辑。要处理"TransientTransactionError",应用程序应显式包含错误的重试逻辑。要查看包含瞬时错误重试逻辑的示例,请参阅 Core API 示例。
UnknownTransactionCommitResult
提交操作是可重试写入操作。如果提交操作遇到错误,那么无论 retryWrites 的值如何,MongoDB 驱动程序都会重试提交。
如果提交操作遇到标记为 "UnknownTransactionCommitResult" 的错误,则可以重试提交。
回调 API 包含
"UnknownTransactionCommitResult"的重试逻辑。核心事务 API 不包含
"UnknownTransactionCommitResult"的重试逻辑。要处理"UnknownTransactionCommitResult",应用程序应显式包含错误的重试逻辑。要查看包含未知提交错误的重试逻辑示例,请参阅 Core API 示例。
TransactionTooLargeForCache
6.2版本新增。
从 MongoDB 6.2 开始,服务器在收到 TransactionTooLargeForCache 错误后不会重试事务。此错误意味着缓存过小,重试可能会失败。
transactionTooLargeForCacheThreshold 阈值的默认值为 0.75。当事务使用超过 75% 的缓存时,服务器会返回 TransactionTooLargeForCache 而不是重试事务。
在 MongoDB 的早期版本中,服务器会返回 TemporarilyUnavailable 或 WriteConflict,而不是 TransactionTooLargeForCache。
使用 setParameter 命令修改错误阈值。
更多信息
mongosh 例子
以下 mongosh 方法适用于事务:
// Create collections: db.getSiblingDB("mydb1").foo.insertOne( {abc: 0}, { writeConcern: { w: "majority", wtimeout: 2000 } } ) db.getSiblingDB("mydb2").bar.insertOne( {xyz: 0}, { writeConcern: { w: "majority", wtimeout: 2000 } } ) // Start a session. session = db.getMongo().startSession( { readPreference: { mode: "primary" } } ); coll1 = session.getDatabase("mydb1").foo; coll2 = session.getDatabase("mydb2").bar; // Start a transaction session.startTransaction( { readConcern: { level: "local" }, writeConcern: { w: "majority" } } ); // Operations inside the transaction try { coll1.insertOne( { abc: 1 } ); coll2.insertOne( { xyz: 999 } ); } catch (error) { // Abort transaction on error session.abortTransaction(); throw error; } // Commit the transaction using write concern set at transaction start session.commitTransaction(); session.endSession();