簡體   English   中英

使用DBIx :: Class :: ResultSet的find_or_create方法時如何避免競爭條件?

[英]How to avoid race conditions when using the find_or_create method of DBIx::Class::ResultSet?

find_or_create的文檔中:

注意:因為find_or_create()從數據庫讀取,然后可能根據結果插入,所以此方法受競爭條件的影響。 查找完成后且開始創建之前,另一個過程可以在表中創建記錄。 為避免此問題,請在事務內使用find_or_create()。

僅在PostgreSQL中的事務內使用find_or_create()就足夠了嗎?

不,文檔不正確。 單獨使用事務無法避免此問題。 它僅保證在發生異常時將回滾整個事務-這樣就不會將不一致的狀態持久化到數據庫中。

避免此問題,您必須鎖定表-在事務內部,因為所有鎖定都在事務結束時釋放。 就像是:

BEGIN;
LOCK TABLE mytbl IN SHARE MODE;

-- do your find_or_create here

COMMIT;

但這並不是萬能的靈丹妙葯。 這可能會成為性能問題,並且可能會出現死鎖 (並發事務相互嘗試鎖定另一個已經鎖定的資源)。 PostgreSQL將檢測到這種情況,並取消所有競爭事務,但其中之一除外。 您必須准備在失敗時重試該操作。

PostgreSQL有關鎖的手冊。

如果您沒有太多的並發性,那么您也可以忽略該問題。 時隙很小,因此實際上很少發生。 如果您發現重復的鍵沖突錯誤,這不會造成任何危害,那么您也已解決了這一問題。

find_or_create此實現應防止出現競爭情況,如OP中所述:

eval {
    $row = $self->model->create( { ... } );
}
if($@ && $@ =~ /duplicate/i) {
   $row = $self->model->find( { ... } );
} 

在最佳情況下,它還將find_or_create()為單個查詢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM