我正在制定一個票務系統,用戶在聲明它們之前立即託管大量票(基本上所有沒有缺貨的票)。這些門票向用戶顯示,他們可以選擇他們想要聲明的任何門票。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