2

I'm using c3p0 and postgres. I have a multi-threaded application where, without proper locking, different threads may accidentally update the same record. In order to prevent this, I intend to use advisory locks.

SELECT pg_advisory_lock(id) FROM ...;

However, I'm not sure whether I can actually use advisory locks in conjunction with connection pooling, since what if the connection that was used to create the locks gets closed (this is transparent to the application logic)? Do the corresponding locks get released?

4

1 回答 1

6

是的,当连接关闭时,锁(建议和其他)会被释放。

但是,如果连接返回到池,它们可能不一定会被释放;事务级锁将是因为池程序将ROLLBACK打开任何事务,但只有当您的连接池程序知道在将会话返回到连接池后运行特定于 PostgreSQL 的DISCARD ALL;语句时,才会释放建议锁。

为了防止这种情况,我打算使用咨询锁。

为什么?您正在阻止更新记录,因此您有一个可以锁定的普通行。您的流程应该是:

  1. 从连接池中检查一个连接
  2. SELECT * FROM the_table WHERE id = 123 FOR UPDATE
  3. 做应用程序中要求的工作
  4. UPDATE the_table SET whatever = blah WHERE id = 123
  5. 将连接返回到连接池

这要求您在三个步骤的同一连接上保持一个打开的事务。如果您的架构阻止您这样做并在 (2) 之后将连接返回到池,那么它可能也阻止使用咨询锁定,因为您需要保持相同的底层连接来管理咨询锁定。

如果是这种情况,您必须使用乐观并发控制(通常称为“乐观锁定”),这是为无状态 Web 应用程序创建的设计。您将版本字段存储在实体中,您的流程类似于:

  1. SELECT col1, col2, entity_version FROM the_table WHERE id = 123(假装entity_version返回值42
  2. 完成应用程序中所需的工作
  3. UPDATE the_table SET whatever = blah, entity_version = 43 WHERE id = 123 AND entity_version = 42

如果entity_version已被另一个会话更改,则该WHERE子句UPDATE将不匹配,并且更新将影响零行。您测试受影响的行数并重试整个操作或在发生这种情况时向用户报告错误。

许多 ORM 已经实现了乐观并发控制,例如 Hibernate 和其他 JPA ORM。您不必将它与 ORM 一起使用,这只是最常见的用途,因为 ORM 鼓励“选择然后更新”反模式,否则 SQL DB 应该避免这种模式。

于 2013-07-24T07:31:56.970 回答