2015-03-30 61 views
4

我有一個表可能有兩個線程從中讀取數據。如果數據處於某種狀態(假設狀態爲1),那麼過程將執行某些操作(與此問題無關),然後將狀態更新爲2.鎖定SELECT以便其他進程不會獲取舊數據

在我看來,可能會出現這樣的情況,線程1和線程2都在相互之間的微秒內執行選擇,並且兩者都看到該行處於狀態1,然後兩者執行相同的操作,並在鎖定釋放後發生2次更新。

問題是:有沒有一種方法可以防止第二個線程能夠修改Postgres中的這些數據 - 也就是在第一個鎖的更新被釋放之後,它被強制執行另一個SELECT,因此它知道爲了防止欺騙?

我看着行鎖定,但它說你不能阻止選擇語句,這聽起來像它不會在我的條件下工作在這裏。我唯一的選擇是使用諮詢鎖嗎?

回答

4

你的問題,引用未知來源:

我看着行鎖定,但它說,你不能阻止選擇 語句這聽起來像它不會對我的病情在這裏工作。我使用諮詢鎖的唯一選擇是 ?

The official documentation on the matter:

行級鎖不影響數據查詢;他們只將作者 和儲物櫃鎖定在同一行。

併發嘗試將不只是選擇而是要設法取出與SELECT ... FOR UPDATE相同的行級鎖 - 這使他們等待任何以前的事務保持在同一行上的鎖提交或回滾。正是你想要的。

但是,許多使用情況最好用advisory locks解決 - 在9.5版本之前。您仍然可以將正在處理的行鎖定爲FOR UPDATE,以確保安全。但是如果下一個事務只是想處理「下一個空閒行」,它通常會更有效,不會等待同一行,這在釋放鎖後幾乎肯定不可用,而是跳到「下一個空閒「馬上。

在Postgres 9.5+考慮爲此FOR UPDATE SKIP LOCKED。像@Craig commented,這可以在很大程度上取代諮詢鎖。

相關問題絆倒相同的性能豬:

說明和代碼例如用於諮詢鎖或Postgres裏FOR UPDATE SKIP LOCKED 9.5+:

要一次鎖定許多行:

+2

請注意,在9.5中,您可以使用'FOR UPDATE SKIP LOCKED'來代替使用諮詢鎖來實現排隊。 http://michael.otacoo.com/postgresql-2/postgres-9-5-feature-highlight-skip-locked-row-level/。方式更容易。 – 2015-03-31 03:46:02

+0

@CraigRinger:好消息。 :) – 2015-03-31 04:14:31

+0

謝謝你們!這個答案有一些更有用的信息,所以我接受了它,但都提出了兩項​​。 – BryanP 2015-03-31 04:19:54

2

你想要的是相當常見的SQL SELECT ... FOR UPDATE。 Postgres特定的文檔是here

使用SELECT FOR UPDATE將鎖定事務跨度的選定記錄,讓您有時間在另一個線程可以選擇之前更新它們。

+1

'之前另一個線程可以select'是有點模糊,因爲選擇仍然是自由成爲可能。我添加了手冊中的原始報價來澄清。 – 2015-03-31 04:27:37

+1

您確實需要將它與'SELECT ... FOR SHARE'或另一個會話的'SELECT ... FOR UPDATE'結合使用,因爲鎖不會阻塞未裝飾的'SELECT'。 – 2015-03-31 04:37:42

相關問題