場景:
- 應用剛上線排除大批量請求的問題
- 線上多次出現的Deadlock found when trying to get lock錯誤

代碼:
async batchUpdate(skus, { transaction }) {
const result = await Promise.all(skus.map(async sku => {
const record = await this.app.model.Sku.upsert(sku, { transaction });
return record;
}));
// SaaS 中刪掉的 sku,插件也要同步洗掉
const ids = _.map(skus, 'sku_id');
const productIds = _.map(skus, 'product_id');
const { Op } = this.app.Sequelize;
await this.app.model.Sku.destroy({
where: {
sku_id: { [Op.notIn]: ids },
product_id: productIds,
}, transaction,
});
return result;
};
分析:
- 報錯位置都是在this.app.model.Sku.destroy的時候報錯
- Deadlock found when trying to get lock的原因是多個事物同事更新插入同一表的某一段資料
- 在資料量不大的情況下,按道理說發生這種死鎖的情況應該非常少但是事實上出現的概率很高
結論:
- 應該是destroy使用notIn會涉及到很多行的鎖定,所以造成了死鎖,但是業務上destroy洗掉的資料一般為0條,所以可以只在必要的時候進行destroy操作,
- 更新的時候少用或不用notIn操作
優化后代碼:
async batchUpdate(skus, { transaction }) {
const result = await Promise.all(skus.map(async sku => {
const record = await this.app.model.Sku.upsert(sku, { transaction });
return record;
}));
// SaaS 中刪掉的 sku,插件也要同步洗掉
const ids = _.map(skus, 'sku_id');
const productIds = _.map(skus, 'product_id');
const { Op } = this.app.Sequelize;
const delSkus = await this.app.model.Sku.findAll({
where: {
sku_id: { [Op.notIn]: ids },
product_id: productIds,
}, transaction,
});
if (delSkus && delSkus.length) {
await this.app.model.Sku.destroy({
where: {
sku_id: delSkus.map(sku => sku.sku_id),
}, transaction,
});
}
return result;
};
- 參考:
- https://www.cnblogs.com/rainy-shurun/p/5166163.html
- https://www.jianshu.com/p/6049b046e7b4
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/25125.html
標籤:SQL Server
