Mongo 数据库事务特性

3 阅读2分钟

MongoDB 数据库事务特性

MongoDB 事务特性的要求

MongoDB 中,事务(Transaction)是处理多文档操作时保持数据一致性的关键特性。MongoDB4.0 版本开始支持多文档事务,但使用事务需要满足一些条件和配置要求。主要包括两个:

  1. 使用副本集(Replica SetMongoDB 的事务功能依赖于副本集(Replica Set)来提供数据的持久性和一致性。因此,要使用事务,必须在副本集环境中运行 MongoDB。 副本集:至少需要一个主节点(Primary)和一个从节点(Secondary),但建议至少配置三个节点以确保高可用性和数据冗余。
  2. 启用多文档事务支持 从 MongoDB 4.0 开始,多文档事务默认启用,但需要确保副本集的成员配置正确,并且所有成员的版本至少为 4.0 或更高。

MongoDB事务API

MongoDB 提供了 startTransactioncommitTransactionabortTransaction 命令来管理事务。

  • startTransaction:显式地开始一个新的事务。在事务中,可以执行多个操作(如插入、更新、删除等),这些操作要么全部成功提交,要么全部回滚。在 MongoDB Shell 中,事务通常通过 session 对象管理。startTransaction 通过 session 对象调用,比如:
const { MongoClient } = require('mongodb');

async function runTransaction(client) {
    const session = client.startSession();
    try {
        // 开始事务
        await session.startTransaction();

        const collection = client.db('mydatabase').collection('mycollection');

        // 在事务中执行操作
        await collection.insertOne({ name: 'Alice', age: 30 }, { session });
        await collection.updateOne({ name: 'Alice' }, { $set: { age: 31 } }, { session });

        // 提交事务
        await session.commitTransaction();
    } catch (error) {
        console.error('Transaction failed:', error);
        // 回滚事务
        await session.abortTransaction();
    } finally {
        session.endSession();
    }
}

(async () => {
    const client = new MongoClient('mongodb://localhost:27017', { useNewUrlParser: true, useUnifiedTopology: true });
    await client.connect();
    try {
        await runTransaction(client);
    } finally {
        await client.close();
    }
})();
  • commitTransaction:提交当前事务中的所有操作。如果事务成功提交,所有操作将永久生效。
session.commitTransaction();
  • abortTransaction:回滚当前事务中的所有操作。如果事务失败或需要取消,调用此命令将撤销所有已执行的操作。
session.abortTransaction();

MongoDB事务隔离级别

MongoDB 支持以下隔离级别: snapshot:这是默认的隔离级别,提供快照隔离,确保事务在提交之前不会看到其他事务的中间状态。 readCommitted:仅在事务中读取已提交的数据。

MongoDB事务的大小限制

MongoDB 对事务的大小和操作数量有限制: 最大事务大小:事务的总大小(包括数据和日志)不能超过 16MB。 最大操作数量:事务中的操作数量不能超过 1000 个。

MongoDB事务的超时限制

MongoDB 事务有默认的超时限制,以防止长时间运行的事务占用资源。默认超时时间为 60 秒,但可以根据需要调整。

MongoDB 启动多个实例,并配置副本集自动化脚本

  • 注: 这里采用的是免安装版本的 [MongoDB](https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-5.0.31.zip) 数据库
#!/bin/bash

# 获取脚本的绝对路径
SCRIPT_PATH=$(realpath "$0")

# 获取脚本所在目录
SCRIPT_DIR=$(dirname "$SCRIPT_PATH")

# 获取向上两层级的路径  output 目录
OUTPUT_DIR=$(realpath "$SCRIPT_DIR/../../")  # 向上两层

# 定义变量
MONGOD_PATH="$OUTPUT_DIR/Software/Mongo/Server/mongod.exe"  # mongod.exe 路径
MONGO_PATH="$OUTPUT_DIR/Software/Mongo/Server/mongo.exe"  # mongo.exe 路径
CONFIG_DB_PATH="C:\\MongoData\\Database\\Config"      # Config 数据库的数据目录
ORDER_DB_PATH="C:\\MongoData\\Database\\Order"      # Order 数据库的数据目录
CONFIG_PORT=27017                                                # Config 数据库的端口
ORDER_PORT=27018                                                # Order 数据库的端口

# 创建数据目录(如果不存在)
mkdir -p "$CONFIG_DB_PATH"
mkdir -p "$ORDER_DB_PATH"

# 启动 Config 数据库实例
echo "正在启动 Config 数据库实例..."
start "" "$MONGOD_PATH" --dbpath "$CONFIG_DB_PATH" --port "$CONFIG_PORT" --replSet config_rs --logpath "$CONFIG_DB_PATH/mongod.log"

# 启动 Order 数据库实例
echo "正在启动 Order 数据库实例..."
start "" "$MONGOD_PATH" --dbpath "$ORDER_DB_PATH" --port "$ORDER_PORT" --replSet order_rs --logpath "$ORDER_DB_PATH/mongod.log"

# 检查 MongoDB 实例是否准备好
function wait_for_mongod() {
    local port=$1
    echo "等待 MongoDB 实例 (端口 $port) 准备好..."
    while ! "$MONGO_PATH" --port "$port" --eval "quit()" >/dev/null 2>&1; do
        sleep 1
    done
    echo "MongoDB 实例 (端口 $port) 已准备好!"
}

# 等待实例启动
wait_for_mongod "$CONFIG_PORT"
wait_for_mongod "$ORDER_PORT"

# 初始化 Config 副本集
echo "正在初始化 Config 副本集..."
echo 'rs.initiate({
  _id: "config_rs",
  members: [
    { _id: 0, host: "localhost:'"$CONFIG_PORT"'" }
  ]
})' | "$MONGO_PATH" --port "$CONFIG_PORT"

# 初始化 Order 副本集
echo "正在初始化 Order 副本集..."
echo 'rs.initiate({
  _id: "order_rs",
  members: [
    { _id: 0, host: "localhost:'"$ORDER_PORT"'" } 
  ]
})' | "$MONGO_PATH" --port "$ORDER_PORT"

# 验证副本集状态
echo "验证 Config 副本集状态..."
"$MONGO_PATH" --port "$CONFIG_PORT" --eval "rs.status()"

echo "验证 Order 副本集状态..."
"$MONGO_PATH" --port "$ORDER_PORT" --eval "rs.status()"

echo "副本集初始化完成!"