假設我有一盤棋存儲在SQL數據庫的東西,如下面的模式:如何防止多個同時SQL更新一盤棋
CREATE TABLE chessgames(
game_id INTEGER,
move_id INTEGER,
move char(4)
};
因此,如果正在進行的遊戲,用game_id 0,具有e4 e5的移動,那麼該表將具有元組(0,1,「e4」)和(0,2,「e5」)。
現在假設客戶端試圖通過同時發送移動d4和Nf3來破壞數據庫。試圖獲得兩個移動處理並有效地嘗試插入元組(0,3,「d4」)和(0,3,「Nf3」),兩者都具有相同的move_id,從而打破了move_id的唯一性。
什麼是確保唯一性的最佳慣用方法?發生在我身上的一種可能性是讓我的C++代碼包含一個互斥列表,每個遊戲一個互斥量。當一招如D4到達時,C++代碼鎖定了相應的遊戲互斥,運行下面的SQL查詢
SELECT move_id, move FROM chessgames WHERE game_id = 0
獲取所有的遊戲動作(在這個例子中我給了這將是E4和e5),C++代碼將執行這些移動並檢查沒有行已經有move_id = 3,然後播放移動以構建當前位置,以便它可以檢查移動d4是否有效。如果它是有效的,則運行
INSERT INTO chessgames VALUES (0, 3, "d4")
將移動存儲在數據庫中,然後釋放該互斥體。
這樣,如果Nf3移動到達的同時它的d4移動處理將被鎖定的互斥鎖阻擋,並且當最終處理Nf3時,它將看到move_id = 3的行已經存在,它會被忽略。
有沒有更好的方法來做到這一點?我的數據庫模式對於我想要做的事情是否合理?
如果客戶端總是按順序發送移動,即(0,1,「e4」),(0,2,「e3」),(0,3,「b4」),那麼對你來說不是更好控制'move_id',只允許'Game_id'和'Move'作爲客戶端的輸入。這樣,你可以在移動時自動增加'move_id'。 – DMK
對不起,如果我不清楚,隱含我的意思是客戶端不會發送'move_id',只發送'Game_id'和'Move' 。但是我沒有看到,如果服務器應該運行多線程並且可能同時處理多個輸入,那麼解決方法是如何正確地增加'move_id'。 – user782220