SELECT 在并发更新期间更新了行
SELECT updated rows during concurrent updates
假设我有一组代码创建一个事务,选择、删除和重新创建一个资源,然后提交,以便更新它:
BEGIN
SELECT * FROM "product" WHERE (code = 'A') FOR UPDATE
DELETE FROM "product" WHERE "product"."id" = 1
INSERT INTO "product" ("id","code","price") VALUES (1,'A',3000) // Updated price
COMMIT
现在,假设此代码同时被 运行 两次,并试图修改同一行:
TX1 - BEGIN
TX1 - SELECT product
TX1 - DELETE product
TX2 - BEGIN
TX2 - SELECT product - This blocks until TX1 has been committed
TX1 - INSERT updated product
TX1 - COMMIT
TX2 - SELECT product - Error occurs here...
如果我使用事务级别 ReadCommitted
,我会返回 0 行。请注意 TX2
是在 TX1
.
中删除产品后创建的
我无法使用 Serializable
或 RepeatableRead
,因为行已更改,我得到pq: could not serialize access due to concurrent update
.
有什么方法可以让 TX2
中的 SELECT
阻塞直到 TX1
完成,然后 SELECT
新更新的行?我使用SELECT...FOR UPDATE
不正确吗?
隔离级别在 PostgreSQL 中如何工作的行为和原因在他们的文档中有很大的总结:
https://www.postgresql.org/docs/9.5/transaction-iso.html#XACT-READ-COMMITTED)。随着
在我看来,重要的是 PostgreSQL 使用乐观锁定进行事务处理。当交易开始时,会拍摄快照并使用它。
手动使用SELECT ... FOR UPDATE
表示在行上使用悲观锁
现在,当您使用 RepeatableRead
时,数据库承诺保证事务隔离。
当TX1
悲观地锁定行时,TX2
等待下一步。如果 TX1
回滚,那么 TX2
可能会继续。但是随着 TX1
提交,TX2
除了回滚和抛出异常以满足隔离级别的承诺之外别无他法。
您可以从这里重新运行 SQL 查询,这将看到数据库状态的更新版本。
所以为了回答你的问题
Is there any way to have the SELECT in TX2 block until TX1 has been
completed, and then SELECT the new updated row?
是的,使用 RepeatableRead
,当 TX2
的查询失败时,再次运行您的查询。
假设我有一组代码创建一个事务,选择、删除和重新创建一个资源,然后提交,以便更新它:
BEGIN
SELECT * FROM "product" WHERE (code = 'A') FOR UPDATE
DELETE FROM "product" WHERE "product"."id" = 1
INSERT INTO "product" ("id","code","price") VALUES (1,'A',3000) // Updated price
COMMIT
现在,假设此代码同时被 运行 两次,并试图修改同一行:
TX1 - BEGIN
TX1 - SELECT product
TX1 - DELETE product
TX2 - BEGIN
TX2 - SELECT product - This blocks until TX1 has been committed
TX1 - INSERT updated product
TX1 - COMMIT
TX2 - SELECT product - Error occurs here...
如果我使用事务级别 ReadCommitted
,我会返回 0 行。请注意 TX2
是在 TX1
.
我无法使用 Serializable
或 RepeatableRead
,因为行已更改,我得到pq: could not serialize access due to concurrent update
.
有什么方法可以让 TX2
中的 SELECT
阻塞直到 TX1
完成,然后 SELECT
新更新的行?我使用SELECT...FOR UPDATE
不正确吗?
隔离级别在 PostgreSQL 中如何工作的行为和原因在他们的文档中有很大的总结: https://www.postgresql.org/docs/9.5/transaction-iso.html#XACT-READ-COMMITTED)。随着
在我看来,重要的是 PostgreSQL 使用乐观锁定进行事务处理。当交易开始时,会拍摄快照并使用它。
手动使用SELECT ... FOR UPDATE
表示在行上使用悲观锁
现在,当您使用 RepeatableRead
时,数据库承诺保证事务隔离。
当TX1
悲观地锁定行时,TX2
等待下一步。如果 TX1
回滚,那么 TX2
可能会继续。但是随着 TX1
提交,TX2
除了回滚和抛出异常以满足隔离级别的承诺之外别无他法。
您可以从这里重新运行 SQL 查询,这将看到数据库状态的更新版本。
所以为了回答你的问题
Is there any way to have the SELECT in TX2 block until TX1 has been completed, and then SELECT the new updated row?
是的,使用 RepeatableRead
,当 TX2
的查询失败时,再次运行您的查询。