gpt4 book ai didi

MySql get_lock 用于并发安全更新插入

转载 作者:太空宇宙 更新时间:2023-11-03 22:57:32 24 4
gpt4 key购买 nike

使用 mysql 数据库在 node.js 中编写 API,我正在实现一个相当标准的模式:

If exists then update
else insert

这当然可以正常工作,直到同时向 api 发出多个请求,此时请求 2 上的 如果存在 可以在请求 1 的插入之前执行,从而导致两条记录而不是一条记录。

我知道处理这个问题的一种方法是确保数据库具有防止重复记录的约束或键,但在这种情况下,确定是否应该插入或更新的规则更加复杂,因此检查需要在代码中完成。

这听起来像是使用互斥锁/锁的好例子。我需要将其分发,因为 api 可能有多个实例作为池/场的一部分运行。

我提出了以下实现:

try {
await this.databaseConnection.knexRaw().raw(`SELECT GET_LOCK('lock1',10);`);
await this.databaseConnection.knexRaw().transaction(async (trx) => {
const existing = await this.findExisting(id);
if (existing) {
await this.update(myThing);
} else {
await this.insert(myThing);
}
});

} finally {
await this.databaseConnection.knexRaw().raw(`SELECT RELEASE_LOCK('lock1');`);
}

这一切似乎工作正常,我的测试现在只产生一个插入。虽然看起来有点暴力/手动。作为 mysql 和 node 的新手(我来自 c# 和 sql server 背景)这种方法是否合理?有更好的方法吗?

最佳答案

理智吗?主观。

技术上安全吗?它可能是 - GET_LOCK() 是可靠的 - 但不像你写的那样。

您忽略了 GET_LOCK() 的返回值,如果获得了锁,则返回 1;如果超时,您没有获得锁,则返回 0;在某些失败情况下,返回 NULL .

正如所写,您将等待 10 秒,然后无论如何都会完成工作,因此,不安全。

这假设您只有一个 MySQL 主服务器。如果你有多个大师或 Galera,它就不起作用,因为 Galera doesn't replicate GET_LOCK()跨所有 Node 。 (Galera 集群是一个由可写主 Node 组成的高可用性 MySQL/MariaDB/Percona 集群,可同步复制,并且能够承受高达 (ceil(n/2) - 1) 的故障/隔离,其中 (ceil(n/2) - 1) em>n 个 Node )。

最好使用 SELECT ... FOR UPDATE 查找并锁定相关行。 ,它会锁定找到的行,或者在某些情况下锁定它们存在的间隙,阻止其他试图捕获相同锁的事务,直到您回滚或提交...但如果这不切实际,请使用 GET_LOCK() 是有效的,但要遵守上面关于返回值的观点。

关于MySql get_lock 用于并发安全更新插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56719410/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com