MongoDB
数据库事务特性
MongoDB
事务特性的要求
在 MongoDB
中,事务(Transaction
)是处理多文档操作时保持数据一致性的关键特性。MongoDB
从 4.0
版本开始支持多文档事务,但使用事务需要满足一些条件和配置要求。主要包括两个:
- 使用副本集(
Replica Set
)MongoDB
的事务功能依赖于副本集(Replica Set
)来提供数据的持久性和一致性。因此,要使用事务,必须在副本集环境中运行MongoDB
。 副本集:至少需要一个主节点(Primary
)和一个从节点(Secondary
),但建议至少配置三个节点以确保高可用性和数据冗余。 - 启用多文档事务支持
从
MongoDB 4.0
开始,多文档事务默认启用,但需要确保副本集的成员配置正确,并且所有成员的版本至少为4.0
或更高。
MongoDB
事务API
MongoDB
提供了 startTransaction
、commitTransaction
和 abortTransaction
命令来管理事务。
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 "副本集初始化完成!"