2017-02-10 91 views
1

全部,如何解決併發問題?

我在我的應用程序中使用MySql 5.7。我試圖使我的保存功能併發安全。我會用一個例子來解釋。

例如: 我有兩個管理員用戶Admin 1和Admin 2.我們有一個產品表,我們有一個產品表條目,產品代碼爲「P1」。假設管理員1和管理員2登錄到系統中,並嘗試同時更新代碼爲「P1」的產品條目。

我需要通知其中一個用戶,您正在嘗試修改的記錄正在被另一個用戶更新,並在一段時間後再次嘗試。

我正在使用事務並沒有改變MySql的默認事務級別(可重複讀取)。我試圖通過使用「SELECT FOR UPDATE」來解決它(包括一個where條件來檢查修改時間)。這個「where」條件將解決那些已經提交的事務的併發問題。但是,如果兩個事務同時開始並且第一個事務在鎖定超時之前被提交,那麼當第二個事務執行時,它會覆蓋第一個事務。

請分享您的想法提前

+0

你可以在臨界區出現之前做一個'LOCK TABLES product WRITE'。不要忘記事後解鎖。 – apokryfos

+0

@apokryfos鎖定整個表到一個完成單個記錄的編輯是不是一個真正有效的解決方案 – Shadow

+0

我想它可以是解決方案之一:使用InnoDB引擎和'選擇...更新' – Wizard

回答

3

感謝嗯,事實上有2個問題在這裏。

首先,其中一個管理員將在該行之前獲得一個鎖,因此假設admin1首先獲取鎖,admin2將排隊直到admin1的事務完成,然後admin2的事務將發生。

所以這一切都由DBMS爲您照顧。

但第二個問題當然是如果admin1和admin2都試圖更新相同的列。在這種情況下,admin1的更新將被admin2的更新覆蓋。如果這是你想要停止的事情,停止這種情況發生的唯一方法就是讓UPDATE更新它的更新。換句話說,更新必須是這樣的

UPDATE table SET col1 = 'NewValue' 
WHERE usual criteria 
    AND col1 = 'Its Original Value' 

因此,這意味着,當你從該行出示原始數據到用戶在表單中,你必須以某種方式記住它的原始狀態是和捕獲其新的狀態,管理員將其更改爲。

當然,PHP代碼也必須寫入以捕獲UPDATE未發生的事實,並返回某些管理員更新失敗的事情。顯示相關列中的新值,並通知他們更新失敗,因爲其他人已經更改了該字段,並讓他們忘記了更改,或將更改應用於其他管理員更新的頂部。

0

您可以使用這種技術來控制它,而無需鎖定表格或控制您應該執行的更新。

創建你的表中的字段,這將是對於註冊表的一個版本:

alter table someTable add column version not null integer default 0; 

會有無需更改任何代碼插入此。

每次用戶獲取註冊表以更新時,請確保它的版本也在對象(或表單,m或任何您在系統中處理實體的方式)中。

然後,您將需要爲您的表創建一個before update trigger,該表將檢查當前註冊表的版本是否仍然相同,以便您更新,如果沒有,則會引發錯誤。就像:

delimiter $$ 
create trigger trg_check_version BEFORE UPDATE 
     ON yourTable 
     for each row 
    begin 
     if NEW.version != OLD.version then 
      signal sqlstate '45000' set message_text = 'Field outdated'; 
     else 
      NEW.version = NEW.version + 1; 
     end if; 
    end$$ 
delimiter; 

然後你在你的php代碼中處理錯誤。這個signal命令僅適用於MySql 5.5或更高版本。看看這個thread