2013-05-20 25 views
1

我在Postgresql上遇到了一些錯誤,這似乎與這種競爭條件有關。我該如何處理PostgreSQL中的競態條件?

我有一個用Twisted Python編寫的進程/守護進程。描述它的最簡單方法就像Web爬蟲一樣 - 它會拉動一個頁面,解析鏈接並記錄看到的內容。由於HTTP阻塞,Twisted會將多個「併發」進程延遲到線程。

這裏的比賽條件...

當我遇到一個短網址,這樣的邏輯發生:

result= """SELECT * FROM shortened_link WHERE (url_shortened = %(url)s) LIMIT 1;""" 
if result: 
    pass 
else: 
    result= """INSERT INTO shortened_link (url_shortened ..." 

一個令人驚訝的數字或psycopg2.IntegrityError的復活,因爲url_shortened唯一索引變侵犯。

select/insert實際上運行在一起。從我所知道的情況來看,它看起來像是兩個縮短的鏈接彼此相鄰排隊。

Process A: Select, returns Null 
Process B: Select, returns Null 
Process A: Insert , success 
Process B: Insert , integrity error 

任何人都可以提出任何提示/技巧來處理這個?我想避免明確的鎖定,因爲我知道這會引發另外一些問題。

回答

2

做這一切在一個單一的命令:

result= """ 
INSERT INTO shortened_link (url_shortened ... 
SELECT %(url)s 
where not exists (
    select 1 
    from shortened_link 
    WHERE url_shortened = %(url)s 
);""" 

如果該鏈接不存在,它只會插入。

+4

這應該處理大部分問題。儘管如此,競爭條件的小小機會依然存在。我爲類似的請求寫了一個答案[here](http://stackoverflow.com/questions/15939902/is-my-function-prone-to-race-conditions/15950324#15950324) –

+1

+1 Erwin的函數。這是唯一一個防爆表或諮詢鎖的防彈解決方案。如果有足夠的併發查詢,則此答案的select語句中競態條件的機會決不會忽略不計。 –

1

您或者需要某種類型的互斥鎖,否則您將不得不忍受由於競爭條件而發生的冗餘。

如果您選擇使用互斥鎖 - 您不一定需要使用數據庫級鎖。您可以簡單地鎖定Twisted進程來阻止處理類似縮短網址的其他線程。

如果您選擇避免鎖定,請刪除url_shortened字段上的唯一約束。您可以定期將這些記錄移到一個「乾淨的」表格中,該表格包含每個縮短網址的唯一唯一副本。

2

真的沒有一種解決方案可以避免需要能夠處理唯一約束違規錯誤的可能性。如果你的框架無法做到這一點,那麼我會將SQL包裝在PL/pgSQL函數或過程that can中。

鑑於您可以處理錯誤,您可能不會測試是否存在唯一值,只需嘗試插入,讓EXCEPTION子句處理任何錯誤。

+0

是的,我現在編寫了一個例外條款。這可能在其他地方發生 - 它似乎真的聚集在這個用例上。嘆。 –

+1

我相信我設計了這樣的解決方案[這裏](http://stackoverflow.com/questions/15939902/is-my-function-prone-to-race-conditions/15950324#15950324)。 –