2017-10-18 74 views
0

我有一個表COMMANDS,用戶同時插入數據。InnoDB表寫鎖,但允許讀取

每插入一次,我必須做一些(耗時)的計算並將結果保存到另一個表RESULTS

與此同時所有用戶也從COMMANDS讀取數據。

我的問題是:

後新$command插入,我使用所有的行該表在我的計算。每行都會影響計算,也可能會影響以前的$commands,因爲我想鎖定此表以獲取新插入,直到進行當前計算並保存結果。但我也不想阻止其他用戶查看當前狀態COMMANDS

不久之後,我想鎖定表格進行寫入而不鎖定讀取。

我使用InnoDB引擎。我讀了一些關於鎖定的文檔,但我完全困惑。

共享和排它鎖,意圖鎖定,差距鎖...

看來愚蠢的,但目前我使用類似下面

public function storeNewCommand($command){ 

    // $busy_flag is an app level global that can be read by all user sessions 

    if($busy_flag){ 
     usleep(10000); 
     return $this->storeNewCommand($command); 
    } 

    $busy_flag = true; //(lock) 

    /* 
    ...insert new $command to COMMANDS 

    ...do calculations using all comands including last one 

    ...store results in RESULTS 
    */ 

    $busy_flag = false; //(unlock) 

} 

我知道必須有更好的和聰明的解決方案的機制這沒有圈和睡覺。但我不知道使用哪一個。

+0

注意如何設置一個隊列,這樣就可以將「用戶輸入過程」從「保存到數據庫過程」中分離出來,並控制如何在計算時避免插入新行。 – Alfabravo

+0

謝謝@Alfabravo我正在使用一些隊列作業,但他們工作異步,並且對每個插入後的所有保存的命令的當前狀態非常重要。所以我想在數據庫級別阻塞插入,如果有一個ongoning計算。 – Jaxovee

+0

對我來說,模仿一個表級鎖是錯誤的策略。不管用戶如何,他們都應該通過相同的隊列和相同的DAO發送他們的請求。 – Alfabravo

回答

1

如果你可以做的長度小於lock_wait_timeout,其中默認爲50秒,然後使用BEGIN ... COMMIT。 (個人而言,我將其限制爲更像2秒,而不是50)。

否則,設計一些其他方法 - 有一個表,每作家榮譽,說你在這個「關鍵」部分」。它可能不需要比具有單行的1列或2列表格多得多。

當抓取該互斥鎖時,一定要將提取,設置等封裝在一個事務中,並對失敗作出反應。獲得鎖定後,繼續執行緩慢的操作。最後放開鎖。

警告:如果發生崩潰或軟件錯誤,釋放鎖的代碼可能永遠不會執行。因此,包含時間戳以及注意互斥體在「很長」時間內未被釋放的情況是很好的。他們可以通過電子郵件向您發送有關問題並清除鎖定的信息