我正在为我们的电子商务提供库存管理服务,因此决定尝试mongodb。在此服务中,我必须实现多文档更新。
我知道mongodb支持事务并且我尝试了,但是看起来非常不稳定。它偶尔会成功,但是大多数情况下会返回此错误:Transaction 1 has been committed.
根据我的调查,解决方案基本上是添加重试逻辑,直到它起作用为止。我认为这不是一个好方法。平均而言,它需要重试10次,并且根据mongodb文档,与其他查询相比,事务处理成本更高。尽管“支持”交易,但mongodb还建议不要依赖交易。
最后,我决定使用服务器端锁定系统(异步锁定模块)来锁定相关库存,同时对其进行更新。现在,这解决了我最大的问题,并发问题。我希望通过使更新部分尽可能简单(除非服务器在进程中途停机)来使整个更新问题的原子性大大减少。但是,这仍然是一个问题。
我也不认为将锁锁定在服务器端是最佳实践。
所以我想知道是否存在正确的NoSQL方法来解决我的事务问题。
让我详细解释我的问题:
股票模式的核心部分看起来像这样(为了简单起见,我删除了一些与此问题无关的字段)
const StockSchema = new Schema({
qty: { type: Number, required: true },
logs: [
{
qty: { type: Number, required: true },
order: { type: ObjectId, ref: 'order', required: true },
}
]
});
下订单时,有些情况下qty
必须从一个以上的stock
文档中递减,因为单个库存不足qty
。
例如,假设一个产品有两个stock
文档:
let stock1 = {
qty: 3,
logs: []
}
let stock2 = {
qty: 5,
logs: []
}
我们刚收到一个需要7个单位的订单。
因此,我们首先从stock1
减少3个单位,从stock2减少剩余的4个单位。
结果应为:
let stock1 = {
qty: 0,
logs: [{ qty: 3, order: 'orderId' }]
};
let stock2 = {
qty: 1,
logs: [{ qty: 4, order: 'orderId' }]
};
这是我的代码:
let { qty } = order;
let stocks = await Stock.find({});
stocks= stocks.map(stock => {
let change = 0;
if (qty === 0) return stock;
if (stock.qty >= qty) {
change = qty;
stock.qty -= qty;
qty = 0;
} else {
change = stock.qty;
qty -= stock.qty;
stock.qty = 0;
}
stock.logs.push({ qty: change, order: orderId });
return stock;
});
await Promise.all(stocks => stock.save()) //all the save occurs almost simultaneously, which is why Im expecting all or nothing issue is less of a problem.