循环插入到 MySql 数据库,无死锁



im 使用 nodejs (AdonisJs( 创建一个脚本来更新我的数据库 (Mysql(。像这样:

const trx = await Database.beginTransaction();
try {
const async = use('async');
await async.eachOfLimit(arr, 50, async item => {
`select * from table1 where id = 1 LOCK IN SHARE MODE`
`insert into ....`
`another query...`
});
trx.commit();
} catch (err) {
trx.rollback();
}

问题是eachOfLimit并行运行查询,因此上面的代码抛出错误:Deadlock found when trying to get lock; try restarting transaction。如果我使用同步循环运行它for of它工作正常。 如何修复此问题或我的脚本的任何想法。对不起,我的英语不好。

顺便说一句,我使用LOCK IN SHARE MODEFOR UPDATE来避免在运行许多查询INSERT重复时,即使我使用findOrCreate来检查行是否存在

您可以尝试使用"用于更新"而不是"共享模式锁定"来防止锁定同一行。

从 dev.mysql.com

选择。。。锁定共享模式

对读取的任何行设置共享模式锁。其他会话可以读取行,但在事务提交之前无法修改它们。如果这些行中的任何一行被尚未提交的另一个事务更改,则查询将等到该事务结束,然后使用最新值。

选择。。。用于更新

对于搜索遇到的索引记录,锁定行和任何关联的索引条目,就像为这些行发出 UPDATE 语句一样。其他事务被阻止更新这些行,执行 SELECT ...锁定在共享模式下,或从读取某些事务隔离级别的数据。一致性读取会忽略在读取视图中存在的记录上设置的任何锁。(无法锁定记录的旧版本;它们是通过在记录的内存中副本上应用撤消日志来重建的。

我找到了一个临时解决方案:使用INSERT IGNORE而不是INSERT。 所以我删除了SELECT查询并使用INSERT IGNORE.

const language = await Database.raw(trx('languages').insert({
...languageItem,
created_at: this.getTimeNow(),
updated_at: this.getTimeNow()
}).toString().replace('insert', 'INSERT IGNORE'));

我的脚本运行没有死锁。

最新更新