PostgreSQL 咨询锁不适用于 Doctrine 的 DBAL

Posted

技术标签:

【中文标题】PostgreSQL 咨询锁不适用于 Doctrine 的 DBAL【英文标题】:PostgreSQL advisory locks are not working with Doctrine's DBAL 【发布时间】:2015-06-04 00:23:01 【问题描述】:

我在 Doctrine 的 DBAL 中尝试使用 advisory locks 时遇到了一种非常奇怪的行为。

我有一个 Symfony 2 应用程序,我想在其中获得某个实体的咨询锁。我正在执行以下查询以获取锁:

SELECT pg_try_advisory_lock(83049, 5)

通过以下 php 代码:

/** @var Doctrine\DBAL\Connection  */
protected $connection;

public function lock()

    return $this->connection->fetchColumn(
        "SELECT pg_try_advisory_lock($this->getTableOid(), $this->entity->getLockingId())"
    );

我创建了以下脚本来测试并发性:

// Obtaining the lock.
$locker->lock();

// Doing something for ten seconds.
sleep(10); 

但是,当我同时运行它时,看起来每个实例都成功获得了锁。此外,在请求终止后,看起来锁会自动释放,即使我没有调用unlock()

为什么会这样?

教义是否对所有请求都使用单一连接?

script 终止后是否会自动释放锁?

【问题讨论】:

【参考方案1】:

13.3.4。咨询锁

PostgreSQL 提供了一种创建锁的方法,该锁具有 应用程序定义的含义。这些被称为咨询锁,因为 系统不会强制使用它们——这取决于应用程序 正确使用它们。咨询锁可用于锁定 不适合 MVCC 模型的策略。例如,一个 咨询锁的常见用途是模拟悲观锁 所谓的“平面文件”数据管理系统的典型策略。 虽然存储在表中的标志可以用于相同的目的, 咨询锁更快,避免表膨胀,并且是自动的 在会话结束时由服务器清理。

在 PostgreSQL 中有两种获取咨询锁的方法: 会话级别或事务级别。一旦在会话级别获得, 一个咨询锁被持有直到显式释放或会话 结束。与标准锁请求不同,会话级咨询锁 请求不遵守事务语义:在 稍后回滚的事务仍将在 回滚,同样解锁是有效的,即使调用 稍后交易失败。一个锁可以被多次获取 拥有过程;对于每个完成的锁定请求,必须有一个 在实际释放锁之前的相应解锁请求。 另一方面,事务级锁定请求的行为更像 常规锁请求:它们在结束时自动释放 事务,并且没有显式的解锁操作。这 行为通常比会话级别的行为更方便 建议锁的短期使用。会话级和 对同一咨询锁标识符的事务级锁请求 将以预期的方式相互阻止。如果会话已经举行 给定的咨询锁,它的附加请求将始终成功, 即使其他会话正在等待锁定;这个说法是真的 无论现有的锁定保持和新请求是否在 会话级别或事务级别。

http://www.postgresql.org/docs/9.1/static/explicit-locking.html

【讨论】:

谢谢,你是对的。我错过了automatically cleaned up by the server at the end of the session 部分。但是为什么多个客户端可以同时获得同一个锁呢? 在尝试更新锁定行时开始等待另一个事务。

以上是关于PostgreSQL 咨询锁不适用于 Doctrine 的 DBAL的主要内容,如果未能解决你的问题,请参考以下文章

用户断开连接后 PostgreSQL 咨询锁仍然存在

为啥递归联合不适用于 PostgreSQL 中的复合类型

PostgreSQL 函数不适用于 WHERE 子句

自动回滚不适用于 Postgresql 上的 liquibase

删除不适用于 Play! 2.4、Slick 3 和 PostgreSQL

Flyway - 自动增量 ID 不适用于 PostgreSQL 中的测试数据