2011-04-12 73 views
1

希望有一些比我更聪明的DBA可以帮助我找到一个我需要做的很好的解决方案。PostgreSQL和锁定

为了便于讨论,我们假设我有一个名为'work'的表,其中有一些列,其中一列是表示来自给定客户端的那行工作的所有权的列。这种情况是,我将有2个客户端连接并轮询一个表以完成工作,当一行(或一些行)出现时,第一个选择行的客户端也将更新它们以暗示所有权,更新将删除这些行返回到任何其他客户端的选择。我的问题是,在这种情况下,我可以使用什么类型的锁定来防止2个客户端同时击中表,并且他们两个都通过select返回相同的行?

+0

将查询,如:更新工作集所有者= clientid所有者为空返回列原子操作?例如:2个客户端同时发出该查询,他们没有机会操纵相同的行? – user483315 2011-04-12 14:49:18

回答

7

使用RETURNING子句的UPDATE语句是执行此操作的方法。

UPDATE table 
SET ownership = owner 
RETURNING (column list); 

参考:

Similar Question

Documentation

+0

在你提供的第一个链接中,我想让自己脱离一点点。那个人正在使用一个事务块并在里面执行更新然后提交它,如果我这样做的话,在事务执行的时候,我的理解是有可能在提交发生之前获取行的版本?如果是这样,在事务之外执行应该正常工作? – user483315 2011-04-12 17:52:43

+0

不。UPDATE语句在符合条件的行上抓取排它锁。先到先得。如果其他交易在第一次交易完成之前也符合条件,则它们将被封锁。如果在这一点上行不再符合标准,那么后续交易将会出现错误,您的应用必须处理并重试。然而,你的标准是多行满足它,但是你限制了回报ala LIMIT,那么随后的交易就会得到未被采纳的下一行。这是MVCC世界的序列化。 – Ketema 2011-04-12 22:26:25

3

我的问题是,在这种情况下,我可以用什么样的锁,以防止2个客户端击中在表同一时间,他们都通过选择返回相同的行?

这里不需要锁定。

UPDATE中,只需指定您只希望脚本在所有者仍为null(假设这是标记未分配任务的方式)的情况下取得该任务的所有权。这应该工作:

UPDATE foo SET owner = ? WHERE id = ? AND owner = ? WHERE owner IS NULL 

如果修改的行数等于你所期望的数量(或@Ketema提出了RETURNING子句返回的结果),那么你就成功地抓住了所有权。


假编辑,因为我注意到,提交这份答案之前,您的评论仅仅是瞬间:

如:2个客户端发出该查询在同一时间,他们没有操纵同一行的机会呢?

正确。您可能需要阅读MVCC。运行交易以外的这些陈述将会做正确的事情。行为里面的交易会有所不同。

+0

'交易中的行为会有所不同。“您能否详细说明一下? – pkoch 2013-01-16 14:00:46

+1

您需要阅读[事务隔离](http://www.postgresql.org/docs/current/static/transaction-iso.html)。根据隔离级别,您可能会发现并非完全正确的事情,即使这样,您可能会遇到死锁或冲突,必须单独处理。 [更多关于维基百科](http://en.wikipedia.org/wiki/Isolation_ \(database_systems \))。 – Charles 2013-01-16 17:25:02