2015-05-22 46 views
0

如何阻止一個線程的事務讀取一行,直到另一個事務完成處理?鎖定Oracle行,使第二個線程無法讀取數據

我在Oracle 11 DB上有一個觸發器表。觸發器表上的一行有一個狀態標誌,用於指示是否需要執行一個進程 - 假設它是觸發電子郵件。有定期輪詢觸發表的abatch進程。這個過程是:觸發

  1. GET X數,其中狀態NOT_SENT X的
  2. 更新狀態觸發在發送
  3. 發送X電子郵件X的
  4. 更新狀態觸發到SENT

但我在集羣環境中運行我的應用程序。所以可能有多個版本的批處理過程並行地觸發觸發器。我想確保競爭性的批處理過程不會拉下相同的觸發器並執行相同的處理,即發送相同的電子郵件。

我正在查看Oracle SELECT FOR UPDATE子句。但是,如果這不符合我的要求,我並不十分清楚。我需要線程A來鎖定觸發器行,並且線程B被阻止讀取或寫入觸發器行。如果SELECT FOR UPDATE阻止線程B讀寫,或者僅阻止線程B寫入,這並非100%清楚。我需要前者。

思想歡迎。

+0

你不能這樣做。在Oracle閱讀中永遠不能被阻止。你只能阻止與你有合同的人。即另一個線程必須嘗試鎖定您持有的同一個鎖。 無論您是否都執行'select .. for update'或使用dbms_lock,都沒關係。 – ibre5041

+0

一般而言,**讀者不會阻止作者和作者不會阻止讀者**。 –

+0

@ ibre5041這與以下Justin Cave的答案相矛盾。他說SELECT FOR UPDATE首先鎖定然後讀取。我會測試確認。 – CodeClimber

回答

2

A SELECT FOR UPDATE鎖定並讀取該行。如果線程A已鎖定該行並且線程B試圖鎖定它,則線程B將阻塞,直到線程A釋放其鎖。因此,如果A和B都在執行SELECT FOR UPDATE,則線程B將等待A完成。

在Oracle中,讀寫器永遠不會被寫入器阻塞,所以其他線程將自由讀取A正在處理的行。他們將無法鎖定行。

當然,如果您的鎖定機制將您的應用程序變成功能單線程的東西,那麼它相反會破壞擁有多個線程的目的。你可能想看看做SELECT FOR UPDATE SKIP LOCKED。這是一個很好的例子how SKIP LOCKED works

+0

如果我使用SELECT FOR UPDATE,將SKIP LOCKED暫時擱置一段時間,那麼即使線程A被鎖定(這是我不想要的),線程B也能夠讀取該行的預更新值, 。正確? – CodeClimber

+0

@CodeClimber - 如果A和B都在執行SELECT FOR UPDATE,則操作的順序是鎖定然後讀取。如果A鎖定了該行,則B嘗試通過「SELECT FOR UPDATE」鎖定該行將阻塞,直到A完成。B將無法繼續閱讀該行,直到它能夠鎖定它爲止。其他會話執行普通的'SELECT'而不是'SELECT FOR UPDATE'將始終能夠讀取行。 –

+0

現在明白了,謝謝。關於這點,我把你的觀點看成是一個僞單線程解決方案。我有點不同意,因爲它只是讀取和更新將阻止的觸發標誌。觸發器的實際處理(在上面的示例中發送郵件)將並行運行。 – CodeClimber

1

在PL/SQL塊(一個觸發器也是PL/SQL塊)中可以使用dbms_lock包。

相關問題