循环插入 MySql 数据库,无死锁
Insert to MySql Database in loop without deadlock
我正在使用 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
运行ning 并行查询,所以上面的代码抛出错误:Deadlock found when trying to get lock; try restarting transaction
。如果我 运行 它与 for of
同步循环,它工作正常。
如何解决这个问题或我的脚本的任何想法。抱歉我的英语不好。
顺便说一句,我使用 LOCK IN SHARE MODE
或 FOR UPDATE
来避免在许多查询 INSERT
运行 时重复,即使我使用 findOrCreate
检查行是否存在
您可以尝试使用 "FOR UPDATE" 而不是 "LOCK IN SHARE MODE" 来防止对同一行的锁定。
SELECT ... 锁定共享模式
在读取的任何行上设置共享模式锁。其他会话可以读取这些行,但在您的事务提交之前不能修改它们。如果其中任何行被另一个尚未提交的事务更改,您的查询将等待该事务结束,然后使用最新值。
SELECT ...更新
对于搜索遇到的索引记录,锁定行和任何关联的索引条目,就像您为这些行发出 UPDATE 语句一样。其他事务被阻止更新这些行,执行 SELECT ... LOCK IN SHARE MODE,或读取某些事务隔离级别的数据。一致读取忽略读取视图中存在的记录上设置的任何锁。 (无法锁定旧版本的记录;通过在记录的内存副本上应用撤消日志来重建它们。)
我找到了一个临时解决方案:使用 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'));
我的脚本运行没有死锁。
我正在使用 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
运行ning 并行查询,所以上面的代码抛出错误:Deadlock found when trying to get lock; try restarting transaction
。如果我 运行 它与 for of
同步循环,它工作正常。
如何解决这个问题或我的脚本的任何想法。抱歉我的英语不好。
顺便说一句,我使用 LOCK IN SHARE MODE
或 FOR UPDATE
来避免在许多查询 INSERT
运行 时重复,即使我使用 findOrCreate
检查行是否存在
您可以尝试使用 "FOR UPDATE" 而不是 "LOCK IN SHARE MODE" 来防止对同一行的锁定。
SELECT ... 锁定共享模式
在读取的任何行上设置共享模式锁。其他会话可以读取这些行,但在您的事务提交之前不能修改它们。如果其中任何行被另一个尚未提交的事务更改,您的查询将等待该事务结束,然后使用最新值。
SELECT ...更新
对于搜索遇到的索引记录,锁定行和任何关联的索引条目,就像您为这些行发出 UPDATE 语句一样。其他事务被阻止更新这些行,执行 SELECT ... LOCK IN SHARE MODE,或读取某些事务隔离级别的数据。一致读取忽略读取视图中存在的记录上设置的任何锁。 (无法锁定旧版本的记录;通过在记录的内存副本上应用撤消日志来重建它们。)
我找到了一个临时解决方案:使用 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'));
我的脚本运行没有死锁。