MongoDB(97)如何在MongoDB中执行分布式事务?

在 MongoDB 4.0 及更高版本中,支持分布式事务,这意味着你可以在多个文档和集合中执行 ACID(原子性、一致性、隔离性、持久性)事务,这些文档和集合甚至可以跨多个分片集合。分布式事务在需要跨多个集合或数据库进行原子操作时非常有用。

一、分布式事务简介

分布式事务允许你将一组读写操作封装在一个事务中,并确保这些操作要么全部成功,要么全部失败。MongoDB 使用二阶段提交协议(2PC)来管理分布式事务。

二、前提条件

  1. MongoDB 版本:分布式事务功能在 MongoDB 4.0 及更高版本中可用。
  2. 分片集群:分布式事务支持跨分片集群的操作,但你也可以在非分片环境中使用事务。

三、使用分布式事务

1. 使用 MongoDB Shell 执行事务

以下是一个使用 MongoDB Shell 在跨集合中执行分布式事务的示例代码。

假设我们有两个集合:accountstransactions。我们要将 accounts 中一个账户的余额减少 $100,并在 transactions 中记录这次交易。

javascript 复制代码
// 连接到 MongoDB
conn = new Mongo();
db = conn.getDB("mydatabase");

// 开始事务会话
session = db.getMongo().startSession();
session.startTransaction();

try {
    // 获取会话数据库
    accountsCollection = session.getDatabase("mydatabase").getCollection("accounts");
    transactionsCollection = session.getDatabase("mydatabase").getCollection("transactions");

    // 执行账户余额更新操作
    accountsCollection.updateOne(
        { _id: 1 },
        { $inc: { balance: -100 } }
    );

    // 插入交易记录
    transactionsCollection.insertOne({
        accountId: 1,
        amount: -100,
        timestamp: new Date()
    });

    // 提交事务
    session.commitTransaction();
    print("Transaction committed.");
} catch (error) {
    // 回滚事务
    print("Transaction aborted due to an error: " + error);
    session.abortTransaction();
} finally {
    // 结束会话
    session.endSession();
}

2. 使用 Node.js 和 Mongoose 执行事务

以下是一个使用 Node.js 和 Mongoose 在跨集合中执行分布式事务的示例代码。

首先,确保你已经安装了 mongoose:

bash 复制代码
npm install mongoose

然后,编写以下代码:

javascript 复制代码
const mongoose = require('mongoose');

const uri = 'mongodb://localhost:27017/mydatabase';
mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true });

const accountSchema = new mongoose.Schema({
    _id: Number,
    balance: Number
});

const transactionSchema = new mongoose.Schema({
    accountId: Number,
    amount: Number,
    timestamp: Date
});

const Account = mongoose.model('Account', accountSchema);
const Transaction = mongoose.model('Transaction', transactionSchema);

async function performTransaction() {
    const session = await mongoose.startSession();
    session.startTransaction();

    try {
        // 执行账户余额更新操作
        await Account.updateOne(
            { _id: 1 },
            { $inc: { balance: -100 } },
            { session: session }
        );

        // 插入交易记录
        await Transaction.create([{
            accountId: 1,
            amount: -100,
            timestamp: new Date()
        }], { session: session });

        // 提交事务
        await session.commitTransaction();
        console.log('Transaction committed.');
    } catch (error) {
        // 回滚事务
        console.log('Transaction aborted due to an error:', error);
        await session.abortTransaction();
    } finally {
        // 结束会话
        session.endSession();
    }
}

performTransaction()
    .then(() => mongoose.disconnect())
    .catch(err => console.error('Error:', err));

四、重要注意事项

  1. 事务大小限制:MongoDB 对事务的大小和操作数量有一定限制。每个事务的 oplog 不能超过 16MB,且事务中的写操作数不能超过 1000。
  2. 写冲突:在高并发环境中,可能会发生写冲突,导致事务失败。你需要在应用程序中处理这些情况,可能需要重试事务。
  3. 性能影响:事务在性能上会有一定的开销,因为需要确保 ACID 属性。因此,只在确实需要事务的情况下使用它们。
  4. 事务超时 :MongoDB 会自动中止运行时间超过 transactionLifetimeLimitSeconds 配置的事务。默认值通常是 60 秒。
  5. 事务隔离性:MongoDB 的事务提供快照隔离级别,这意味着在事务开始时看到的数据快照在整个事务期间保持一致。

五、总结

分布式事务在处理需要跨集合或数据库的原子操作时非常有用。通过使用二阶段提交协议,MongoDB 确保了事务操作的原子性和一致性。无论是在 MongoDB Shell 中,还是在应用程序代码中(例如使用 Node.js 和 Mongoose),你都可以灵活地使用事务来确保数据的完整性。请务必注意其使用的限制和性能影响,确保在需要的情况下合理使用事务。

相关推荐
2601_9498177210 小时前
Spring Boot3.3.X整合Mybatis-Plus
spring boot·后端·mybatis
uNke DEPH11 小时前
Spring Boot的项目结构
java·spring boot·后端
zhenxin012211 小时前
Spring Boot 3.x 系列【3】Spring Initializr快速创建Spring Boot项目
spring boot·后端·spring
前端一小卒12 小时前
前端工程师的全栈焦虑,我用 60 天治好了
前端·javascript·后端
不停喝水12 小时前
【AI+Cursor】 告别切图仔,拥抱Vibe Coding: AI + Cursor 开启多模态全栈新纪元 (1)
前端·人工智能·后端·ai·ai编程·cursor
oyzz12012 小时前
Spring EL 表达式的简单介绍和使用
java·后端·spring
zhenxin012212 小时前
【wiki知识库】07.用户管理后端SpringBoot部分
spring boot·后端·状态模式
码事漫谈12 小时前
OpenSpec 简明教程
后端
程序员小假13 小时前
向量检索的流程是怎样的?Embedding 和 Rerank 各自的作用?
java·后端