我正在制定一个票务系统,用户在声明它们之前立即托管大量票(基本上所有没有缺货的票)。这些门票向用户显示,他们可以选择他们想要声明的任何门票。MySQL INSERT SELECT WHERE竞赛条件
该中介系统可以引入竞争条件,如果两个用户尝试到托管在同一时间同一门票和没有足够的门票,如:
剩票:1次
用户A命中页面,检查剩余票数。剩余1张票 用户B击中该页面,检查剩余票数。剩余1张票
既然他们都有票剩余,他们都会托管票,使票左-1。
我想避免,如果在所有可能的,我想知道,如果像
INSERT INTO ticket_escrows (`ticket`,`count`)
SELECT ticket,tickets_per_escrow FROM tickets WHERE tickets.total > (
COALESCE(
SELECT SUM(ticket_escrows.count) FROM ticket_escrows
WHERE ticket_escrows.ticket = tickets.id
AND ticket_escrows.valid = 1
,0)
+
COALESCE(
SELECT SUM(ticket_claims.count)
FROM ticket_claims
WHERE ticket_claims.ticket = tickets.id
,0)
)
与子查询语句将是原子,并允许我来防止竞争条件无锁锁。
具体来说,我想知道,如果上面的查询将防止发生如下:
Max tickets: 50 Claimed/Escrowed tickets: 49
T1: start tx -> sums ticket escrows --> 40
T2: start tx -> sums ticket escrows --> 40
T1: sums ticket claims --> 9
T2: sums ticket claims --> 9
T1: Inserts new escrow since there is 1 ticket left --> 0 tickets left
T2: Inserts new escrow since there is 1 ticket left --> -1 tickets left
我使用的是InnoDB。
“*我想尽量避免锁定*” - 为什么?即使该语句是原子的(我认为它可能取决于您的隔离级别),它的原子性将通过使用锁来实施... – eggyal 2013-05-29 03:48:15
您应该锁定UserA的行,因此当UserB的查询命中该表时,它将等待“ INSERT'完成并获得正确的门票数量,即0。 – Stoleg 2013-05-29 12:13:33
不应在第一个子查询中有SELECT ID,ticket_per_escrow? – Mifeet 2013-05-30 15:43:56