事务
概述
在本指南中,您可以学习如何使用C驱动程序执行事务。事务允许您执行一系列只有在整个事务提交后才会更改数据的操作。如果事务中的任何操作不成功,库将停止事务并丢弃所有更改的数据,这些更改在此之前永远不会可见。此功能称为原子性。
在MongoDB中,事务在逻辑会话中运行。会话是一组相关读或写操作,您打算依次运行。会话使一组操作能够实现因果一致性,并允许您在符合ACID的事务中运行操作,这是指满足原子性、一致性、隔离性和持久性的预期。MongoDB保证参与事务操作的数据保持一致,即使在操作遇到意外错误时也是如此。
使用C驱动程序时,您可以从mongoc_client_t
实例创建一个新的会话。然后,您可以使用生成的mongoc_client_session_t
实例执行事务。
警告
仅使用与创建它的mongoc_client_t
(或相关的mongoc_database_t
或mongoc_collection_t
)一起使用的mongoc_client_session_t
。使用不同mongoc_client_t
的mongoc_client_session_t
会导致操作错误。
事务API
在本节中,您可以了解C驱动程序提供的事务API。在开始事务之前,您必须使用 mongoc_client_start_session()
函数在您的 mongoc_client_t
实例上创建一个 mongoc_client_session_t
。然后,您可以使用以下任一API来执行事务
便捷API
C驱动程序提供了一种名为 便捷事务API 的API来管理事务生命周期。通过使用 mongoc_client_session_with_transaction()
函数在事务中运行自定义回调来实现此API。该 mongoc_client_session_with_transaction()
函数执行以下任务
启动事务
通过结束事务或重试来处理错误,例如当操作结果为
TransientTransactionError
时提交事务
本指南的 事务示例 部分演示了如何使用此API执行事务。
核心API
或者,您可以通过使用以下函数与您的 mongoc_client_session_t
实例来对您的交易生命周期有更多控制。
函数 | 描述 |
---|---|
mongoc_client_session_start_transaction() | 在此会话上启动一个新的交易,配置为给定的选项。如果存在无效参数,例如会话中已存在一个正在进行的交易,则返回 false 并设置提供的错误。有关此函数的更多信息,请参阅服务器手册中的 startTransaction() 页面。 |
mongoc_client_session_abort_transaction() | 结束此会话的活跃事务。如果会话没有活跃事务或事务已被提交或结束,则返回 false 并设置提供的错误。有关此函数的更多信息,请参阅服务器手册中的 abortTransaction() 页面。 |
mongoc_client_session_commit_transaction() | 提交此会话的活跃事务。如果会话没有活跃事务或事务已被结束,则返回错误。有关此函数的更多信息,请参阅服务器手册中的 commitTransaction() 页面。 |
mongoc_client_session_destroy() | 中止任何进行中的事务并结束此会话。释放与此会话相关联的所有客户端资源。 |
有关获取 mongoc_client_session_t
属性和修改可变会话属性的函数的更多信息,请参阅 API 文档。
事务示例
此示例定义了一个回调函数,用于修改 sample_bank
数据库中用于银行交易的集合中的数据。代码执行以下操作:
定义回调函数,该函数接收
mongoc_client_session_t
实例作为参数。创建
mongoc_collection_t
实例以访问目标集合。指定要转账的账户编号和金额。
更新客户的余额以反映转账。
记录带有时间戳的交易收据。
如果事务提交成功,则打印一条消息。
bool transaction_callback (mongoc_client_session_t *session, void *ctx, bson_t **reply, bson_error_t *error) { BSON_UNUSED(ctx); BSON_UNUSED(reply); mongoc_client_t *client = mongoc_client_session_get_client (session); mongoc_collection_t *checking = mongoc_client_get_collection (client, "sample_bank", "checking"); mongoc_collection_t *savings = mongoc_client_get_collection (client, "sample_bank", "savings"); mongoc_collection_t *receipts = mongoc_client_get_collection (client, "sample_bank", "receipts"); const char *account_id = "123456"; int transfer_amount = 1000; bson_t *filter = BCON_NEW ("account_id", BCON_UTF8 (account_id)); bson_t *update_decrement = BCON_NEW ("$inc", "{", "balance", BCON_INT32 (-transfer_amount), "}"); bson_t *update_increment = BCON_NEW ("$inc", "{", "balance", BCON_INT32 (transfer_amount), "}"); if (!mongoc_collection_update_one (checking, filter, update_decrement, NULL, NULL, &error)) { fprintf (stderr, "Failed to update checking account: %s\n", error.message); return false; } if (!mongoc_collection_update_one (savings, filter, update_increment, NULL, NULL, &error)) { fprintf (stderr, "Failed to update savings account: %s\n", error.message); return false; } bson_t *receipt = BCON_NEW ("account_id", BCON_UTF8 (account_id), "amount", BCON_INT32 (transfer_amount), "timestamp", BCON_DATE_TIME (bson_get_monotonic_time ())); if (!mongoc_collection_insert_one (receipts, receipt, NULL, NULL, &error)) { fprintf (stderr, "Failed to insert receipt: %s\n", error.message); return false; } mongoc_collection_destroy (checking); mongoc_collection_destroy (savings); mongoc_collection_destroy (receipts); bson_destroy (filter); bson_destroy (update_decrement); bson_destroy (update_increment); bson_destroy (receipt); printf ("Transaction successful!"); return true; }
然后,运行以下代码以执行事务。此代码完成以下操作:
通过使用
mongoc_client_start_session()
函数从客户端创建一个会话。调用
mongoc_client_session_with_transaction()
函数来管理事务,并将会话和回调作为参数传递。
mongoc_client_session_t *session = mongoc_client_start_session (client, NULL, NULL); if (!session) { fprintf (stderr, "Failed to start session\n"); mongoc_client_destroy (client); return EXIT_FAILURE; } bool result = mongoc_client_session_with_transaction (session, (mongoc_client_session_with_transaction_cb_t) transaction_callback, NULL, NULL, NULL, &error); if (!result) { fprintf (stderr, "Transaction error: %s\n", error.message); } mongoc_client_session_destroy (session); mongoc_client_destroy (client); mongoc_cleanup ();
Transaction successful!
更多信息
有关本指南中提到的概念,请参阅 MongoDB 服务器手册中的以下页面
有关 ACID 兼容性的更多信息,请参阅 MongoDB 网站上的 数据库管理系统中的 ACID 属性是什么? 文章。
API 文档
有关本指南中讨论的任何类型或函数的更多信息,请参阅以下 API 文档