Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> MongoDB

Khóa giao dịch (Transaction lock) trong MongoDB?

Lưu ý quan trọng: MongoDB **hỗ trợ Multi-document ACID Transactions từ phiên bản 4.0** (Replica Set) và 4.2 (Sharded Cluster). Bài viết gốc nói "không hỗ trợ" là đã cũ. Tuy nhiên, mẫu thiết kế findOneAndUpdate để mô phỏng khóa (lock) ứng dụng (application-level lock) vẫn hữu ích cho các phiên bản cũ hoặc trường hợp không muốn dùng transaction đầy đủ.

1. Tạo bộ sưu tập và chèn dữ liệu

> db.demo404.insertOne({ "FirstName": "John" });
> db.demo404.insertOne({ "FirstName": "Robert" });
> db.demo404.insertOne({ "FirstName": "Mike" });

2. Xem dữ liệu

> db.demo404.find();

Kết quả: 3 tài liệu John, Robert, Mike.

3. Mô phỏng Lock bằng findOneAndUpdate (Atomic)

Ý tưởng: Thêm trường in_transaction: true vào tài liệu đầu tiên **chưa bị khóa** ($exists: false). Thao tác này **atomic** - chỉ 1 client thành công.

> var result = db.demo404.findOneAndUpdate(
    { "in_transaction": { $exists: false } },
    { $set: { "in_transaction": true } }
);

4. Kết quả: Trả về tài liệu ĐÃ KHÓA (trước khi update)

{ "_id": ObjectId("5e6f8c38fac4d418a0178592"), "FirstName": "John" }

Tài liệu này giờ có in_transaction: true. Client khác chạy lại sẽ nhận tài liệu tiếp theo (Robert).

5. Giải phóng Lock

> db.demo404.updateOne(
    { _id: result._id },
    { $unset: { "in_transaction": "" } }
);

So sánh với Transaction thật (MongoDB 4.0+):

const session = db.getMongo().startSession();
session.startTransaction();
try {
    db.demo404.updateOne({ _id: id1 }, { $set: { ... } }, { session });
    db.demo404.updateOne({ _id: id2 }, { $set: { ... } }, { session });
    session.commitTransaction();
} catch (e) {
    session.abortTransaction();
} finally {
    session.endSession();
}

Khi nào dùng pattern findOneAndUpdate lock? Hệ thống phân tán đơn giản, rate limiting, leader election, hoặc MongoDB < 4.0.