postgresql - PREPARE TRANSACTION 释放锁?

标签 postgresql transactions msdtc 2phase-commit

我一定错过了一些关于 PostgreSQL 和 PREPARE TRANSACTION 的两阶段提交的内容。

以下 SQL:

BEGIN; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1

给出以下锁:

4092    Private 329373  acc     15/53295    RowExclusiveLock    Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092    Private 329369  acc     15/53295    RowExclusiveLock    Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092    Private 328704  acc     15/53295    RowExclusiveLock    Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092    Private 327169  acc     15/53295    RowExclusiveLock    Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092            acc 15/53295    15/53295    ExclusiveLock   Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092    Private 329377  acc     15/53295    RowExclusiveLock    Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092            acc     15/53295    ExclusiveLock   Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1

交易准备好后:

PREPARE TRANSACTION 'TEST'

锁不见了。

由于 PREPARE 和 COMMIT 之间存在较小的延迟,因此另一个查询可能会获取旧版本的记录。

是否有配置设置可以避免这种行为,或者是设计使然?

提前致谢。

编辑:我在 Windows x64 上使用 PostgreSQL 9.2.2(PostgreSQL 9.2.2,由 Visual C++ build 1600 编译,64 位)

编辑2:以下是完整的测试用例:

在新 session 中发出以下内容:

BEGIN; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1
PREPARE TRANSACTION 'TEST';

然后在另一个新 session 中:

SELECT * FROM person.tcities

您将获得旧版本的记录。

最佳答案

我无法在 PostgreSQL 9.2 上重现所描述的行为:

 CREATE TABLE prep_test AS SELECT generate_series(1,10) AS x;

 BEGIN;
 UPDATE prep_test SET x = x*10;
 PREPARE TRANSACTION 'test';

然后在第二个 session 中:

 UPDATE prep_test SET x = x*20;

按照预期阻止,直到我COMMIT PREPARED 'test'ROLLBACK PREPARED 'test'

在测试可序列化隔离时我也得到了预期的结果:

A# BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
B# BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
A# INSERT INTO prep_test(x) VALUES (42);
B# INSERT INTO prep_test(x) VALUES (43);
A# SELECT count(x) FROM prep_test;
B# SELECT count(x) FROM prep_test;
A# PREPARE TRANSACTION 'test';
B# COMMIT;

B 失败并出现可序列化错误,正如预期的那样。如果 B 也尝试PREPARE TRANSACTION,也会发生同样的情况。

使用测试用例更新问题后:

您的测试用例对我来说看起来很好,即它的行为应该与描述的完全一致并且执行时不会出现错误。

PREPARE TRANSACTION 不是提交。您仍然可以ROLLBACK PREPARED。因此,在您执行最后的 COMMIT PREPARED 之前,PostgreSQL 无法向您显示更改的行,否则如果您读取这些行然后执行 ROLLBACK PREPARED,则会出现脏读异常>.

如果您在运行第二个命令之前没有在第一个 session 中PREPARE TRANSACTION,您将从测试用例中得到相同的结果。它与准备好的交易无关。您只是没有看到未提交事务更改的行,这是完全正常的。

如果两个事务都是SERIALIZABLE,那么它仍然没问题。可串行性要求存在有效的顺序,其中并发事务可以连续发生以产生相同的结果。在这里,这是显而易见的:SELECT 首先出现,然后是 UPDATE。当 SELECT 发生时,事务仍然彼此并发发生,因为使用 PREPARE TRANSACTION 准备的事务在提交或回滚之前仍然处于打开状态.

关于postgresql - PREPARE TRANSACTION 释放锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17092561/

相关文章:

sql - ON 子句中的列是否需要索引?

json - PostgreSQL 9.3 : Adding new Fields to JSON Type

sql-server - Entity Framework : how to find transaction isolation level in SQL Profiler?

Codeigniter 一笔交易有两种模型

.net - Active Directory 事务感知吗?

ado.net - 当 TransactionScope 升级到 DTC 时,.net 4.0 中的场景发生了哪些变化?

ruby - 这个 Ruby PSQL 是安全的吗?

sql - PostgreSQL: CAST() as money: 指定货币

c# - 仅用于选择数据的 TransactionScope 是否需要调用 Complete()

c# - 使用 TransactionScope 的间歇性 System.ArgumentNullException