2016-07-30 43 views
-1

有沒有辦法鎖定一個表,指定只有具有特定值的插入應該被阻止?
比如我有表「任務」並表「子任務」我需要一個操作,即當任務也被關閉屬於其子任務,並仍處於打開狀態應該關閉。所以我想:數據庫如何鎖定表僅用於具有特定值的特定INSERT?

  1. 開始事務
  2. 鎖表子任務但只能防止與給定任務ID的插入可以進行
  3. 關閉所有的子任務
  4. 關閉任務使用樂觀鎖定(如果任務版本改變了所有回滾)
  5. 提交交易

是否可以做我在第2步中描述的內容?如果沒有(或者如果有更好的方法),我怎樣才能在這種情況下獲得安全的併發性?

回答

0

不能鎖定一個表的特定值,但在你的情況下,該解決方案將適用:在子任務,並在此觸發檢查創建插入觸發器如果corespondent任務關閉。如果任務已關閉,則不允許插入。

在任務的另一個觸發將盡快任務關閉關閉所有corespondent子任務。

+0

不幸的是這種解決方案不能在我的情況下應用,因爲如果插入(線程B)發生時線程A關閉了所有的子任務,但沒有關閉它會導致不一致的主要任務。 順便說一句,如果這是不可能的,這裏唯一的解決方案似乎是鎖定整個子任務表。 Tnx – user2572526

+0

我不認爲這個問題應該存在,因爲postgres函數是單個事務。任務觸發器將作爲單個事務運行,並且不能關閉任務並打開核心子任務。 – Victorqedu

1

的最佳方式是自己創建的行!但是您可以在交易結束時刪除它。這是怎麼一回事呢

CREATE OR REPLACE FUNCTION .... 
AS $$ 

    BEGIN 

     INSERT INTO subtasks VALUE(pk, ...) ON CONFLICT (id) DO NOTHING; 
     GET DIAGNOSTICS inserted = ROW_COUNT 

     if inserted THEN 
      DELETE from subtasks where pk = id 
     endif; 
    COMMIT; 
$$ LANGUAGE plpgsql; 

注意,在上面的代碼INSERT ON CONFLICT實際上並沒有要對現有數據進行任何更改。它將返回已更改的行數。如果沒有行被改變,那麼插入的變量將保持爲零。

這裏發生的事情是,具有插入一條記錄在您的交易,任何其他連接將無法保存相同的記錄。您可以通過使用psql打開與數據庫的連接來確認這一點。然後做

begin; 
    insert ... 

    # just wait here 
commit; 

而在另一個,嘗試相同的插入,你會看到它掛起。插入是否成功取決於您是在第一個psql連接中提交還是回滾。

+0

嗨,謝謝你的回答,但我不確定它是否適用於我的情況(但也許我誤解了它)。爲什麼它應該阻止向給定任務添加子任務? – user2572526

+0

請參閱更新 – e4c5

+0

不應該在非唯一列上使用ON CONFLICT。 在這種情況下,列子任務(taskId)不是唯一的,因爲許多子任務可以具有與父任務相同的任務。 Otherwhise在子任務的pk列(即子任務(subtaskId))上使用ON CONFLICT應該不起作用,因爲第二個線程可以插入帶有不同ID的子任務,該子任務尊重由第一個子任務插入的子任務的ID,所以它不會衝突 – user2572526