2017-09-06 38 views
0

据我所知,PostgreSQL使用MVCC来处理并行事务,但我不知道在以下情况下会发生什么:Postgresql事务“COMMIT”线程安全吗?

Client1      Client2      Time 
------------------------------------------------------------------- 
BEGIN       BEGIN      time=t0 
Update row where id=1 Update row where id=1    time=t1 
COMMIT      COMMIT      time=t2 

无论是客户端将在时间启动事务= T0,更新同一行ID为= 1,并且将在时间= t2提交事务。由于提交是在同一时间完成的(时间= t2),它们将被并行执行还是由PostgreSQL按顺序执行?如果它们并行运行,是否有数据损坏的可能性?谢谢。

编辑:“COMMIT”与libPQ一起使用。在psql中,COMMIT = END。

+1

这两个更新不可能同时发生**。第二个更新将等到第一个提交(或回滚) –

+0

谢谢。我对并发事务的很多场景感到困惑。非常感谢你纠正我。我从你的评论中得到了答案。 – Saurabh

回答

1

这篇文章充满了误解。

还有这里没有涉及线程,所以它根本不是“线程安全”的。 PostgreSQL使用多个进程,每个连接一个进程。客户端应用程序可能不会共享线程之间的单个连接,除非它们确保它们执行适当的锁定以一次停止使用它的多个线程。

你问的是关于并发性,而不是线程。而你并没有真正询问“线程安全性”,而是关于原子性和隔离性。 See the PostgreSQL documentation chapter on concurrency control

在这种情况下:

  • 快照取自访问该数据库的第一条语句,所以他们在时间t1(更新)采取非T2(提交)。在这种情况下,两个UPDATE都会影响同一行。他们会锁定这一行,然后等到另一个提交或回滚。那时候,等待中的人会重新检查它的WHERE条款是否仍然匹配,然后它会继续进行自己的更改。
  • 明确的COMMITBEGIN这里是噪声,它们并不重要,因为如果您单独运行语句,它们会自动包装在单个语句事务中。

所以

由于提交的在同一时刻(时间= T2)

他们不能在完全相同的时间内完成,因为他们采取简单的锁更新完成一些共享内存数据结构并写入事务日志。但他们确实重叠。从逻辑上讲,一个仍然在另一个之前提交。

您似乎认为只有在您提交时才会生效。这不是真的。语句立即运行,所以这些UPDATE在您发送它们后立即运行。其他交易只有才会变为可见,直到提交。

如果它们并行运行,是否有数据损坏的可能性?

不,这就是PostgreSQL和其他RDBMS的全部意义。不会有数据损坏

在这种情况下,两个UPDATE将通过使用行锁定将它们自行排序。如果你在这里尝试了你在做什么,在两个并发会话中,但是不要提交它们,然后查询pg_locks,你会看到一个正在等待另一个。

结果可能与如果您连续运行两个事务而不是同时运行会发生什么不同。我们将在PostgreSQL文档的事务隔离章节中详细讨论这个问题,并举例说明。

交易不是神秘的秘密酱,让你忽略并发问题。如果您使用SERIALIZABLE事务,则它们距离它不太远,但是您的应用必须准备好重试任何事务,因为它们可能由于序列化失败而随时失败。 (无论如何,编写良好的应用程序可以做到这一点,因为即使是READ COMMITTED xacts也可能因死锁等原因而失败)。