在 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 的支援特性。