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 MODE
或FOR 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'));
我的脚本运行没有死锁。