我面临着一个看似简单的问题,但事实却很难解决。我们希望保留每次获得营销(线索)的记录,因此在90天内不要购买超过一次。许多潜在客户提供商经常会同时多次向我们提供相同的潜在客户。我们希望将“接受”返回给恰好一个潜在客户提供商。
因此,让我们谈谈可行的方案:我们已经查看了过去90天内的材料,并在桌子上有记录,并且有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返回Thread1:
+-----------+
| 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现在立即将其返回到所有三个线程,而以前只有一个线程可以继续执行:
+-----------+
| 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理想地阻塞。
谢谢你, -乔纳森
答案 0 :(得分:0)
因此,我们最终放弃了锁定。相反,我们在单独的事务中提交该行,然后选择减去last_insert_id()
的电子邮件的所有行。如果发现行的主键较低,则假定另一个线程已经在处理请求。很好,因为它是无锁的,调试起来有点容易。