我正在寻找一种方法来管理Postgres中多个表的乐观并发控制。我还试图保持数据库的业务逻辑 out 。我有一个像这样的表格设置:
CREATE TABLE master
(
id SERIAL PRIMARY KEY NOT NULL,
status VARCHAR NOT NULL,
some_value INT NOT NULL,
row_version INT NOT NULL DEFAULT(1)
)
CREATE TABLE detail
(
id SERIAL PRIMARY KEY NOT NULL,
master_id INT NOT NULL REFERENCES master ON DELETE CASCADE ON UPDATE CASCADE,
some_data VARCHAR NOT NULL
)
每当行更新时, master.row_version
会自动增加一个触发器。
客户端应用程序执行以下操作:
master
表中读取记录。detail
表。如果自从在步骤1读取记录后master.row_version
的值发生了变化,我希望第3步被拒绝。乐观的并发控制在我看来似乎是正确的答案(唯一的答案?),但是我我不知道如何在这两个表中管理它。
我认为Postgres中的一个函数在master
表中的相关记录上有row-level lock可能是要走的路。但是我不确定这是否是我最好的/唯一的选择,或者看起来是什么样的(我在Postgres语法上有点绿色)。
我正在使用Npgsql,因为客户端应用程序是用C#编写的。我不知道其中有什么可以帮助我吗?我想尽可能避免使用函数,但是我很难找到一种方法来使用直接SQL来执行此操作,并且匿名代码块(至少在Npgsql中)不支持I / O操作。需要。
答案 0 :(得分:3)
如果您想使用乐观并发控制,则锁定已关闭,请参阅以下主题的the Wikipedia article:
OCC假设多个交易可以经常完成 相互干扰。在运行时,事务使用数据 资源没有锁定这些资源。
您可以使用更复杂的INSERT
语句。
如果$1
是原row_version
且$2
且$3
master_id
和some_data
要插入detail
,请运行< / p>
WITH m(id) AS
(SELECT CASE WHEN master.row_version = $1
THEN $2
ELSE NULL
END
FROM master
WHERE master.id = $2)
INSERT INTO detail (master_id, some_data)
SELECT m.id, $3 FROM m
如果row_version
已更改,则会尝试将NULL
作为detail.id
插入,这将导致
ERROR: null value in column "id" violates not-null constraint
您可以将其转换为更有意义的错误消息。
答案 1 :(得分:-2)
我已经得出结论,行锁可以用于“典型的”悲观并发控制方法,但是当与行版本结合使用时,可以产生具有一些有意义的好处的“混合”方法。
不出所料,悲观,乐观或“混合”并发控制的选择取决于应用程序的需求。
典型的悲观并发控制方法可能如下所示。
master
表中读取(并锁定)记录。detail
表。如果步骤3中的业务逻辑长时间运行,这种方法可能是不合需要的,因为它会导致长时间运行的事务(通常是不利的),以及master
中记录的长期锁定可能在并发方面存在问题。
仅使用乐观并发控制的方法看起来可能更像这样。
master
表中读取记录(包括行版本)。master
表中记录的行版本(乐观并发控制检查)。detail
表。在这种情况下,数据库事务的保留时间较短,任何(隐式)行锁都是如此。 但是,master
表中记录的行版本的增量可能会对并发操作产生误导。想象一下这个场景的几个并发操作,他们将开始对乐观并发检查失败,因为行版本已经增加,即使记录上有意义的属性没有被更改。
“混合”方法同时使用悲观锁定和(有点)乐观锁定。
master
表中读取记录(包括行版本)。master
表中的记录 AND 锁定行。< / LI>
detail
表。如果步骤4无法获取记录,则应将此视为乐观并发控制检查失败。记录自步骤1以来已更改,因此业务逻辑不再有效。
与典型的悲观并发控制方案一样,这涉及事务和显式行锁,但事务+锁的持续时间不再包括执行业务逻辑所需的时间。
与乐观并发控制方案一样,记录需要一个版本。但它的不同之处在于版本没有更新,这意味着取决于该行版本的其他操作不会受到影响。
混合方法可能有利的一个例子:
博客有一个post
表和comment
表。仅当post.comments_locked
标记为false
时,才能将评论添加到帖子中。添加注释的过程可以使用混合方法,确保用户可以在没有任何并发异常的情况下同时添加注释。
博客的所有者可以编辑他们的post
,在这种情况下,可以采用传统的乐观并发控制方法。博客的所有者可以具有长时间运行的编辑过程,该过程不会受到添加评论的用户的影响。当post
更新到数据库时,版本将递增,这意味着任何正在进行的注释添加操作都将失败,但可以使用数据库获取方法重新获取{{} {1}}从数据库中记录并重试该过程。