MySql 中有 select … for update 來加讀鎖,那麼對應地在 DocumentDB中 如何加讀鎖

gongchengship發表於2024-07-09

在 AWS DocumentDB(MongoDB 相容版)中,沒有像 MySQL 中的 SELECT ... FOR UPDATE 語法來直接加讀鎖。AWS DocumentDB 主要依賴 MongoDB 的讀寫操作和事務支援來管理併發訪問和資料一致性。以下是在 AWS DocumentDB 中處理併發訪問和資料一致性的一些方法:

1. 事務支援

AWS DocumentDB 支援 MongoDB 4.0 相容的事務操作。透過使用事務,可以確保在一組操作中實現原子性、一致性、隔離性和永續性(ACID 特性)。在事務中執行的操作會在提交之前進行鎖定,確保其他事務不會對相同的文件進行修改。

示例程式碼:

import com.mongodb.client.MongoClients;
import com.mongodb.client.ClientSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ProductService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Transactional
    public void purchaseProduct(String productId, int quantity) {
        ClientSession session = mongoTemplate.getSession();
        try {
            session.startTransaction();

            Product product = mongoTemplate.findById(productId, Product.class);
            if (product != null && product.getQuantity() >= quantity) {
                // Deduct from inventory
                product.setQuantity(product.getQuantity() - quantity);
                mongoTemplate.save(product);

                // Record transaction
                Transaction transaction = new Transaction(productId, quantity);
                mongoTemplate.save(transaction);
            }

            session.commitTransaction();
        } catch (Exception e) {
            session.abortTransaction();
            throw e;
        }
    }
}

2. Pessimistic Locking

儘管 AWS DocumentDB 不直接支援 SELECT ... FOR UPDATE 型別的鎖定語法,但可以透過程式設計實現悲觀鎖定(Pessimistic Locking)。在讀取文件時,透過使用 ClientSession 和事務來實現鎖定效果,確保其他事務不會在你處理完畢之前修改文件。

示例程式碼:

import com.mongodb.client.MongoClients;
import com.mongodb.client.ClientSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;

@Service
public class ProductService {

    @Autowired
    private MongoTemplate mongoTemplate;

    public void purchaseProductWithLock(String productId, int quantity) {
        ClientSession session = mongoTemplate.getSession();
        session.startTransaction();

        try {
            // Lock document for update
            Product product = mongoTemplate.findById(productId, Product.class);
            if (product != null && product.getQuantity() >= quantity) {
                // Deduct from inventory
                product.setQuantity(product.getQuantity() - quantity);
                mongoTemplate.save(product);

                // Record transaction
                Transaction transaction = new Transaction(productId, quantity);
                mongoTemplate.save(transaction);
            }

            session.commitTransaction();
        } catch (Exception e) {
            session.abortTransaction();
            throw e;
        }
    }
}

3. 使用樂觀鎖定 (Optimistic Locking)

另一種方式是透過實現樂觀鎖定來確保併發修改的一致性。在 AWS DocumentDB 中,可以透過在文件中新增版本號(例如 _version 欄位),在更新操作時比較版本號,如果版本號不匹配則拒絕更新,從而避免併發衝突。

示例程式碼:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.data.mongodb.core.FindAndModifyOptions;

@Service
public class ProductService {

    @Autowired
    private MongoTemplate mongoTemplate;

    public boolean purchaseProduct(String productId, int quantity) {
        Query query = new Query(Criteria.where("_id").is(productId).and("quantity").gte(quantity));
        Product product = mongoTemplate.findAndModify(
                query,
                new Update().inc("quantity", -quantity),
                new FindAndModifyOptions().returnNew(true),
                Product.class
        );

        return product != null;
    }
}

總結

雖然 AWS DocumentDB 不支援類似 MySQL 的 SELECT ... FOR UPDATE 的直接讀鎖操作,但可以透過事務、悲觀鎖定和樂觀鎖定等方式來管理併發訪問和資料一致性。選擇合適的併發控制方式取決於你的應用需求和 AWS DocumentDB 的支援特性。

相關文章