MySQL: 如何保持锁并让其他线程等待尚未发生的插入
MySQL: How to hold lock and make other threads wait for an insert that hasn't happened yet
我遇到了一个看似简单的问题,但结果却很难弄清楚。我们希望记录每次收到营销信息(线索)的时间,这样我们在 90 天内不会购买超过一次。许多潜在客户提供者可以多次向我们展示相同的潜在客户,通常是同时进行。我们想要 return 一个 "accept" 给一个主要提供者。
那么让我们谈谈有效的场景:我们 在过去 90 天内看到了 material 并且在 table 上有记录并且有 3 个提供者同时呈现领先优势:
select count(id) from recent_leads where
last_seen_at >= '2019-10-11 00:00:00'
and email = 'yes@example.com' for update;
线程1先到,获得锁。 MySQL returns 到线程 1:
+-----------+
| count(id) |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)
Thread1 发出新插入:
insert into recent_leads (email, last_seen_at)
values ('yes@example.com', '2019-12-12 18:23:35');
线程 2 和线程 3 将阻止尝试执行相同的语句,直到线程 1 提交或对其事务发出回滚。然后Thread2和Thread3竞争锁,同样的过程。
所以它按预期工作,我们对此很满意。当 没有 记录时,轮子就会脱落。
线程 1、线程 2 和线程 3 都发出与上面相同的 SQL。 MySQL 现在 return 将此立即发送到 所有三个 线程,而之前,只有一个线程会继续:
+-----------+
| count(id) |
+-----------+
| 0 |
+-----------+
1 row in set (0.00 sec)
所有三个线程现在都尝试插入。其中两个会报错:
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
有没有办法让我们 MySQL 一直表现得像第一种情况?我们希望 Thread2 和 Thread3 理想地阻塞。
谢谢,
-乔纳森
所以我们最终放弃了锁定。相反,我们在单独的事务中提交该行,然后 select 返回电子邮件的所有行减去 last_insert_id()
。如果我们找到具有较低主键的行,我们假设另一个线程已经在处理该请求。这很好,因为它是无锁的,更容易调试。
我遇到了一个看似简单的问题,但结果却很难弄清楚。我们希望记录每次收到营销信息(线索)的时间,这样我们在 90 天内不会购买超过一次。许多潜在客户提供者可以多次向我们展示相同的潜在客户,通常是同时进行。我们想要 return 一个 "accept" 给一个主要提供者。
那么让我们谈谈有效的场景:我们 在过去 90 天内看到了 material 并且在 table 上有记录并且有 3 个提供者同时呈现领先优势:
select count(id) from recent_leads where
last_seen_at >= '2019-10-11 00:00:00'
and email = 'yes@example.com' for update;
线程1先到,获得锁。 MySQL returns 到线程 1:
+-----------+
| count(id) |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)
Thread1 发出新插入:
insert into recent_leads (email, last_seen_at)
values ('yes@example.com', '2019-12-12 18:23:35');
线程 2 和线程 3 将阻止尝试执行相同的语句,直到线程 1 提交或对其事务发出回滚。然后Thread2和Thread3竞争锁,同样的过程。
所以它按预期工作,我们对此很满意。当 没有 记录时,轮子就会脱落。
线程 1、线程 2 和线程 3 都发出与上面相同的 SQL。 MySQL 现在 return 将此立即发送到 所有三个 线程,而之前,只有一个线程会继续:
+-----------+
| count(id) |
+-----------+
| 0 |
+-----------+
1 row in set (0.00 sec)
所有三个线程现在都尝试插入。其中两个会报错:
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
有没有办法让我们 MySQL 一直表现得像第一种情况?我们希望 Thread2 和 Thread3 理想地阻塞。
谢谢, -乔纳森
所以我们最终放弃了锁定。相反,我们在单独的事务中提交该行,然后 select 返回电子邮件的所有行减去 last_insert_id()
。如果我们找到具有较低主键的行,我们假设另一个线程已经在处理该请求。这很好,因为它是无锁的,更容易调试。