2013-01-14 54 views
0

我有一個數據庫和一個表(innoDB):表。塊併發mysql更新查詢

此表中的行是:m1和m2。

我在一個頁面上有2個提交按鈕。

提交1做到這一點:

Database::q('UPDATE table SET m1 = ?s, m2 = ?i WHERE id = ?i', $n, 0, $ID); 

提交2做到這一點:

Database::q('UPDATE table SET m2 = ?s WHERE id = ?i', $n2, $ID); 

的問題:如果用戶提交的DET同時兩種形式。可以說在提交1時爲100 000($ n),在提交2時爲50($ n2)。 結果將在更新之後:m1爲99 950,m2爲100 000。

我該如何預防? 我嘗試使用交易,但它仍然無法正常工作。

該語法正確嗎?我不明白什麼時候使用一個:exec,query,execute?

try { 
    Database::beginTransaction(); 
    Database::q('..'); 
    Database::commit(); 
} catch (Exception $e) { 
    Database::rollBack(); 
    echo 'ERROR!'; 
} 

這是databass類我使用: http://pastebin.com/PfsiYysX

+0

什麼數據庫引擎?如果你想要符合ACID的行爲,使用InnoDB而不是MyIsam。 –

+0

即時通訊使用InnoDB – medusa1414

+0

我不明白你的例子,100萬爲n1 => m1 = 100000,m2 = 0; 50在n2 => m2 = 50;你怎麼能在m1上獲得99 950? – regilero

回答

0

正如馬丁所說,有些javascript會阻止意外按下兩個按鈕。然而,它並不適用於所有情況,當然也不能保護這兩種形式的有意散佈。但是,這會阻止大多數用戶到達您對操作應用真正有效的控制點。

更安全的解決方案是將單次使用的CSRF令牌(兩種形式的相同令牌的副本)合併 - 在第一次請求時檢查並過期令牌。這樣做的問題是,如果用戶分割會話(打開新窗口),用戶可能會認爲存在故障。有一些方法可以緩解這一點 - 但這取決於應用程序如何實現的具體細節。

更好的解決方案是將其建模爲有限狀態機,當數據處於初始狀態但不允許後續更新時允許進行更新。我已經提供了一個示例,但這不可能從您提供的數據中獲得。所以請考慮一下:用戶已經填滿購物籃並前往結帳處。此時他們有兩種選擇 - 進行購買或放棄購物籃。如果他們點擊「進行購買」,如果是這樣,那麼如果購物籃狀態爲「結帳時」,則將狀態設置爲「購買」,如果這是成功的,則繼續進行購買處理。如果他們點擊'丟棄',那麼如果成功,您將籃子狀態更改爲狀態爲'結帳'時的'丟棄',然後繼續清理。如果任一操作不成功,則報告錯誤。請注意,每個操作都應該自動提交 - 並且不使用鎖定。

+0

我用ajax同時提交了兩個按鈕。 '$阿賈克斯({ 類型: 「POST」, URL: 「URL」, xhrFields:{withCredentials:真正}, 數據:{M1: 「VAL」,M2: 「VAL」}, 完成:函數(){} });' 用CSRF解決它。謝謝! – medusa1414

0

如果用戶提交的DET同時

兩種形式意味着你有2個HTTP請求到1個文件或者或2個獨立的PHP文件 - 並不重要。在任何情況下都沒有辦法(也沒有交易)來避免這個問題。

事務用於保護需要一個接一個執行的一堆查詢。在執行之前,他們必須被sql引擎知道。有兩個請求,發送不同的單語句查詢,這是不可能的。

一種解決方法是通過javascript來禁用按鈕2,而按下1則反之亦然。但這隻適用於啓用js的行爲良好的客戶端(無安全措施!)。