我知道PostgreSQL使用MVCC来处理并行事务,但我不确定在以下场景中会发生什么:
Client1 Client2 Time
-------------------------------------------------------------------
BEGIN BEGIN time=t0
Update row where id=1 Update row where id=1 time=t1
COMMIT COMMIT time=t2
两个客户端都将在time = t0启动事务,在time = t1时在各自的快照中更新id = 1的同一行,并在time = t2时提交事务。由于提交是在同一时刻完成的(时间= t2),它们是并行执行还是由PostgreSQL按顺序执行?如果它们并行运行,是否存在数据损坏的可能性?感谢。
编辑:“COMMIT”与libPQ一起使用。在psql中,COMMIT = END。
答案 0 :(得分:2)
这篇文章充满了误解。
此处没有涉及线程,因此它不是"线程安全"一点都不PostgreSQL使用多个进程,每个连接一个。客户端应用程序可能不会在线程之间共享单个连接,除非它们确保它们执行适当的锁定以阻止多个线程一次使用它。
您要问的是并发性,而不是线程。并且您并没有真正询问线程安全"但关于原子性和孤立性。 See the PostgreSQL documentation chapter on concurrency control
在这种情况下:
READ COMMITTED
中,每个后续语句都有自己的快照UPDATE
都会影响同一行。他们将锁定该行,并且将等待另一个提交或回滚。那时,等待的人会重新检查它的WHERE
子句是否仍然匹配,然后它将继续进行自己的更改。COMMIT
和BEGIN
是噪音,它们并不重要,因为如果您单独运行这些语句,它们会自动包含在单个语句事务中。所以
由于提交是在同一时刻完成的(时间= t2)
它们无法在完全相同的时间完成,因为它们会使用简短的锁来更新某些共享内存数据结构并写入事务日志。但他们确实重叠。逻辑上,一个仍然在另一个之前提交。
您似乎认为语句仅在您提交时生效。那不是真的。语句立即运行,因此这些UPDATE会在您发送后立即运行。在提交之前,这些更改不会对其他交易显示。
如果它们并行运行,是否存在数据损坏的可能性?
不,这是PostgreSQL和其他RDBMS的重点。没有数据损坏。
在这种情况下,两个UPDATE将使用行锁定在它们之间进行排序。如果您在两个并发会话中尝试完全正在执行的操作,但不提交,则查询pg_locks
您将看到一个正在等待另一个。< / p>
如果您以串行方式而不是并发方式运行两个事务,那么的结果可能会有什么不同。在PostgreSQL文档的事务隔离章节中详细讨论了这一点。
交易不是神奇的秘密酱,让你忽略并发问题。如果您使用SERIALIZABLE
个交易,它们离它不太远,但您的应用必须准备好重试任何交易,因为它们可能因序列化失败而随时失败。 (编写良好的应用程序无论如何都可以这样做,因为即使READ COMMITTED
xacts因死锁等原因也会失败。)