MongoDB 如何执行事务/加锁?

参考回答

MongoDB 支持 事务(Transactions)锁机制 来确保数据一致性和操作的原子性。事务允许在多个文档和多个集合之间执行 ACID(原子性、一致性、隔离性、持久性)操作,而锁机制用于控制并发访问以防止数据不一致。


MongoDB 事务

1. 单文档事务

  • MongoDB 的单文档操作(如插入、更新和删除)本身是原子的。
  • 如果应用场景只涉及单个文档,不需要显式使用事务。

2. 多文档事务

  • 在需要跨多个文档或集合执行一致性操作时,可以使用事务。
  • 多文档事务仅在 副本集(Replica Set)分片集群(Sharded Cluster) 中受支持。

事务使用示例

在副本集环境中执行事务

步骤
1. 启动事务:
使用 startTransaction 开启事务。
2. 执行操作:
在事务范围内执行读写操作。
3. 提交或回滚事务:
根据需要选择 commitTransactionabortTransaction

示例(Node.js):

const { MongoClient } = require('mongodb');

async function runTransaction() {
    const client = new MongoClient('mongodb://localhost:27017');
    await client.connect();
    const session = client.startSession();

    try {
        session.startTransaction();

        const db = client.db('myDatabase');
        const users = db.collection('users');
        const orders = db.collection('orders');

        // 操作 1:更新用户余额
        await users.updateOne({ _id: 1 }, { $inc: { balance: -100 } }, { session });

        // 操作 2:记录订单
        await orders.insertOne({ userId: 1, amount: 100 }, { session });

        // 提交事务
        await session.commitTransaction();
    } catch (error) {
        // 发生错误,回滚事务
        await session.abortTransaction();
        console.error('Transaction aborted:', error);
    } finally {
        await session.endSession();
        await client.close();
    }
}

runTransaction();
JavaScript
在分片集群中执行事务
  • 事务在分片集群中支持,但所有集合必须启用分片。
  • 操作会通过 mongos 路由到相应的分片。

MongoDB 的锁机制

1. 锁的类型

MongoDB 使用分层锁(Granularity Locks),以提升并发性能。以下是主要的锁类型:

  1. 全局锁(Global Lock)
    • 影响整个数据库实例的锁。
    • 适用于维护操作(如备份、分片平衡)。
  2. 数据库锁(Database Lock)
    • 作用于单个数据库。
  3. 集合锁(Collection Lock)
    • 作用于单个集合。
  4. 文档锁(Document Lock)
    • MongoDB 采用文档级锁(Document-Level Lock),这是默认锁粒度,用于控制单个文档的并发访问。

2. 锁的读写模式

MongoDB 的锁分为 共享锁(读锁)独占锁(写锁)
1. 读锁
– 多个读操作可以并发执行,但会阻止写操作。
2. 写锁
– 写操作需要独占锁,阻止其他读和写操作。


3. 查看锁状态

可以使用以下命令查看当前锁的状态:

db.serverStatus().locks
JavaScript

示例返回:

{
    "Global": {
        "acquireCount": { "r": 100, "w": 10 },
        "timeAcquiringMicros": { "r": 5000, "w": 2000 }
    },
    "Database": {
        "acquireCount": { "r": 50, "w": 5 }
    },
    "Collection": {
        "acquireCount": { "r": 30, "w": 2 }
    }
}
JSON
  • r:读锁。
  • w:写锁。

MongoDB 事务与锁机制的比较

功能 事务(Transaction) 锁机制(Locks)
作用范围 跨文档、跨集合或跨数据库的操作。 单个数据库、集合或文档的并发控制。
隔离级别 提供多种隔离级别(如读未提交、可重复读等)。 通过读锁和写锁控制数据一致性。
场景 多文档或多集合的原子操作。 控制文档级并发访问,提升性能。
对性能的影响 开启事务会增加一定的资源开销。 锁机制更轻量,粒度越小并发性能越高。

事务的注意事项

  1. 性能开销
    • 事务会增加资源使用,如内存和锁时间。
    • 应尽量缩小事务的执行时间,避免阻塞其他操作。
  2. 超时时间
    • 默认事务的最大持续时间为 60 秒(可配置)。
    • 超时后,事务会自动回滚。
  3. 事务隔离级别
    • MongoDB 默认提供 读未提交(Read Uncommitted) 隔离级别。
    • 需要更高隔离级别时,可以结合 snapshot 功能使用。

总结

MongoDB 提供了 事务锁机制 来确保数据一致性:
1. 事务
– 用于跨文档、跨集合甚至跨数据库的复杂操作,支持 ACID 特性。
– 适用于需要严格一致性的场景(如金融系统)。

  1. 锁机制
    • 用于控制并发访问,主要是文档级锁(Document-Level Lock),粒度更细。
    • 提升了高并发环境下的性能。

合理选择事务和锁机制,能在保障数据一致性的同时,最大化系统性能。

发表评论

后才能评论