场景:javascript
- 应用刚上线排除大批量请求的问题
- 线上屡次出现的Deadlock found when trying to get lock错误
代码:html
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; };
分析:java
- 报错位置都是在this.app.model.Sku.destroy的时候报错
- Deadlock found when trying to get lock的缘由是多个事物同事更新插入同一表的某一段数据
- 在数据量不大的状况下,按道理说发生这种死锁的状况应该很是少可是事实上出现的几率很高
结论:app
- 应该是destroy使用notIn会涉及到不少行的锁定,因此形成了死锁。可是业务上destroy删除的数据通常为0条。因此能够只在必要的时候进行destroy操做。
- 更新的时候少用或不用notIn操做
优化后代码:async
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; };