【发布时间】:2015-08-19 20:21:50
【问题描述】:
在 postgres 中进行并发更新时,我得到一个
错误:由于并发更新,无法序列化访问
有没有办法让事务等到另一个事务完成,而不是因为错误而失败?
这是我的测试用例:
-- SESSION 1
START TRANSACTION;
SET SESSION TRANSACTION ISOLATION LEVEL Serializable;
SELECT pg_sleep(5); -- 5 second delay
UPDATE users SET nonce = nonce + 1 WHERE u_id = 'dude';
COMMIT;
另一个会话(会话 2)同时发生
-- SESSION 2
START TRANSACTION;
SET SESSION TRANSACTION ISOLATION LEVEL Serializable;
UPDATE users SET nonce = nonce + 1 WHERE u_id = 'dude';
COMMIT;
如何让事务在执行前等待前一个事务完成。截至目前,它不会执行,只会报告错误,这让我在我的服务器上管理故障逻辑。我可以使用类似事务队列的东西吗?或者可能是一个检查是否有其他事务正在进行的语句,然后等待它解决?
(注意:我使用的是 postgres,并且我的事务隔离设置为可序列化)
编辑:
我通过一些小的修改解决了这个问题。 我将事务隔离更改为已提交读,并在更新语句后移动了 5 秒延迟。
延迟在更新语句之后很重要,因为数据库在读取更新语句之前不会在行上放置块。
这是修改后的测试用例:
-- SESSION 1
START TRANSACTION;
SET SESSION TRANSACTION ISOLATION LEVEL Read committed;
UPDATE users SET nonce = nonce + 1 WHERE u_id = 'dude';
SELECT pg_sleep(5); -- 5 second delay
COMMIT;
另一个会话(会话 2)同时发生
-- SESSION 2
START TRANSACTION;
SET SESSION TRANSACTION ISOLATION LEVEL Read committed;
UPDATE users SET nonce = nonce + 1 WHERE u_id = 'dude';
COMMIT;
在这种情况下,会话 2 事务在提交自身之前等待会话 1 事务提交。
【问题讨论】:
-
为什么要在事务中设置
autocommit = 1? -
如果您一次只更新一行,我认为没有必要更改默认的事务隔离级别。您这样做是为了避免什么问题?
-
@DondiMichaelStroma 我认为更好地描述我想要的内容是在我遇到并发错误的情况下重复事务的一种方式。
-
好吧,在
Read committed中,并不是整个事务都在等待另一个事务完成,而是一个语句等待一个对象被解锁。如果你同时运行两者,我会说第二个首先完成(因为没有理由不这样做)。 -
@BrianSmith 我明白了,我问的问题是你为什么要首先使用
SERIALIZABLE隔离级别?
标签: database postgresql transactions