繁体   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