我想要某个用户锁定一行,直到他无限期地使用这一行,他必须在完成后将其解锁。所以其他任何用户都无法为自己锁定这一行。可以在数据库级别上进行吗?
答案 0 :(得分:1)
您可以使用长期交易执行此操作,但会出现性能问题。这听起来更像是乐观并发控制的工作。
你可以只是打开一个交易并执行SELECT 1 FROM mytable WHERE clause to match row FOR UPDATE;
。然后保持交易开放,直到完成为止。这样做的问题是它可能导致真空问题导致表和索引膨胀,其中表填充了已删除的数据,索引填满了指向过时块的条目。
使用advisory lock要好得多。您仍然必须保持锁定打开的连接,但它不必保持打开的空闲事务,因此它的影响要小得多。希望更新行的事务必须显式检查是否存在冲突的建议锁,否则它们就可以像未锁定一样继续进行。这种方法也很难扩展到许多表(由于有限的咨询锁命名空间)或大量并发锁(由于连接数)。
如果无法确保客户端应用程序始终明确获得咨询锁定,您可以使用触发器检查建议锁定并等待它。但是,这可能会造成死锁问题。
出于这个原因,最好的方法可能是有一个记录用户ID的locked_by
字段,以及一个记录锁定时间的locked_time
字段。在应用程序级别和/或使用触发器执行此操作。要处理获取锁定的并发尝试,您可以使用optimistic concurrency control技术,其中设置WHERE
和UPDATE
的{{1}}上的locked_by
子句不匹配如果其他人先到达那里,那么行数将为零,你就会知道你失去了锁定的竞争并且必须重新检查。该locked_time
子句通常会测试WHERE
和locked_by
。所以你写的东西是:
locked_time
(这是一种简化的乐观锁定模式,用于获取锁定,您不介意其他人跳入并执行整个事务。如果您想要更严格的排序,则使用行版本列或者检查last_modified列未更改。)