3

假设我想以读取提交模式(在 postgres 中)执行以下事务。

T1: r(A) -> w(A)
T2: r(A) -> w(A)

如果按此顺序调用操作:

r1(A)->r2(A)->w1(A)->c1->w2(A)->c2

我预计 T2 必须在 r(A) 处等待。因为 T1 在第一次读取时会为 A 设置一个排他锁,因为它想稍后再写入。但是使用 MVCC 就没有读锁了吗?

现在我有两个问题:

如果我使用 JDBC 读取一些数据,然后执行一个单独的命令来插入读取的数据。数据库如何知道它只在读取时必须进行排他锁?据我所知,在 2PL 中不允许将读锁增加到写锁。

我认为我的假设是错误的......这种情况在哪里等待或一个事务被杀死?未提交的读取不应该允许丢失更新,但我看不出这是如何工作的。

如果有人可以帮助我,我会很高兴。谢谢

4

3 回答 3

1

“但是使用 MVCC 就没有读锁了吗?”

MVCC 是一个不同的野兽。MVCC 中没有“锁”,因为在这种情况下,系统会维护并发运行的事务可能需要的单行的多个版本。行的“以前的内容”不会“被更新丢失”(即物理覆盖和破坏),因此确保读者不会看到“新更新”,通过“重定向”读者的查询来解决“以前的内容”,未锁定(因此称为“快照隔离”)。请注意,MVCC 原则上不能应用于更新事务。

“如果我使用JDBC读取一些数据,然后执行单独的命令插入读取的数据。数据库怎么知道它只在读取时必须做一个排他锁?增加一个读锁到一个写锁不是据我所知,在 2PL 中是允许的。”

你对 2PL 的看法是错误的。2PL 意味着获取的锁在提交之前永远不会释放。这并不意味着无法加强现有的锁。顺便说一句:这就是为什么诸如“游标稳定性”之类的隔离级别不是 2PL 的原因:它们确实会在提交时间之前释放读锁。

于 2011-05-21T11:15:37.020 回答
0

PostgreSQL 中的默认事务模式是 READ COMMITTED,但是 READ COMMITTED 不提供您正在寻找的序列化级别。

您正在寻找 SERIALIZABLE 事务级别。阅读 PostgreSQL 的Transaction Serialization Levels文档后,查看SET TRANSACTION命令,特别是SERIALIZABLE 模式。PostgreSQL 的MVCC 文档也值得一读。

干杯。

于 2011-05-20T17:51:50.113 回答
0

我预计 T2 必须在 r(A) 处等待。因为 T1 在第一次读取时会为 A 设置一个排他锁,因为它想稍后再写入。但是使用 MVCC 就没有读锁了吗?

如果您for update在选择语句中指定,则存在写锁。在这种情况下,如果 r2(A) 试图锁定与 r1(A) 相同的行,它会等待读取。

http://www.postgresql.org/docs/9.0/interactive/explicit-locking.html

如果两个事务开始并最终请求对方已经锁定的行,则会发生死锁:

r11(A) -> r22(A) -> r12(A) (same as r22) vs r21(A) (same as r11) -> deadlock
于 2011-05-20T18:31:41.023 回答