2014-09-06 19 views
0

我擔心我的數據庫支持應用程序中的競爭條件。我的應用程序允許用戶在課堂上預定一個位置。如果所有的斑點都被採納了,那麼他們被置於等待名單上。在大大簡化了僞代碼,我做的是這樣的:當更新基於事先選擇的計數時避免競爭條件

1 spots = SELECT total_spots FROM classes WHERE class_id = 200; 
2 regs = SELECT COUNT(*) FROM registrations WHERE class_id = 200; 
3 wl = spots > regs 
4 INSERT INTO registrations (user_id, class_id, on_waitlist) VALUES (500, 200, wl); 

如果total_spotsclasses表發生變化,或其他用戶不會在registrations表剛過,我們讀它的INSERT會發生什麼(第2行) 。

在事務中包裝整個事物是否足夠?我在MySQL中讀了一些關於SELECT FOR UPDATE的信息。我目前正在使用SQLite,但如果有必要,我可以遷移到MySQL。

回答

1

SQLite的交易are fully atomic

如果您將整個事件包裝在一個事務中,則到同一數據庫的其他連接不能同時進行任何更改。

+0

不只是保證所有** **更新執行或回滾。當我讀取SQLite [docs](http://sqlite.org/lang_transaction.html)時,在事務內部,第一次讀取時會得到一個「SHARED」鎖,第一次寫入時會得到一個「RESERVED」鎖。在持有'SHARED'鎖定時(即,在第4行更新之前),不能再寫入其他進程? – 2014-09-06 14:18:45

+1

共享鎖可防止其他人獲取預留鎖。 – 2014-09-06 14:36:09

1

您還可以將插件內選擇:

insert into registrations (user_id, class_id, on_waitlist) 
values (500, 200, 
    (SELECT total_spots FROM classes WHERE class_id = 200) < 
    (SELECT COUNT(*) FROM registrations WHERE class_id = 200) 
); 
+0

這是我處理它的首選方式,但我給出的例子大大簡化了。有許多檢查是在允許註冊之前執行的。我不確定我可以在一個聲明中得到他們。 – 2014-09-06 14:11:38

+0

然後交易是你的朋友。 – 2014-09-06 14:15:55