【发布时间】:2018-02-05 23:03:35
【问题描述】:
我在 CentOS Linux 上使用 PostgreSQL 9.3.12。
我有两个进程连接到同一个数据库,使用“已提交”的默认事务隔离级别。根据 postgres 文档,事务中的一个进程在提交之前不应“看到”事务中另一个进程所做的更改。
我看到的一个序列是:
- 进程 A 开始其事务
- 进程 A 删除表 T 中的所有内容
- 进程 B 开始其事务
- 进程 B 尝试选择更新表 T 中的一行
- 进程 B 出现空(0 行)并调用回滚
- 进程 A 从传入数据重新填充表 T
- 进程 A 提交其事务
现在,应该在两个事务开始之前填充表 T,并且进程 B 的查询应该出现一行。如果这些进程没有同时运行,它也会这样做。
我的理解是进程 B 应该看到表 T 中所需行的旧副本,进行更改,并且这些更改应该被进程 A 删除和重新填充表 T 破坏。我不知道为什么进程B 空了。
除了我自己对这些先决条件的完全误解之外,谁能想到我会看到这种行为的另一个原因?
不要担心糟糕的架构,它正在消失。我只是想了解为什么这种情况似乎违反了我理解的“已提交”事务隔离。
谢谢。
【问题讨论】:
-
您是否可以使用“TRUNCATE TABLE”删除所有内容。我认为这不是事务性的。根据手册:“TRUNCATE 不是 MVCC 安全的。”
-
不,这是一个 DELETE FROM。
-
您使用哪些工具,您确定您的流程按预期交错运行吗?您是否使用“开始交易”?在我看来,B 真的不应该在 A 提交之前看到删除,而我在 postgres 方面的经验也从未如此。
-
听起来好像进程 A 实际上处于自动提交模式
-
您看到的可能与 MVCC 相关——“每个 SQL 语句都会看到一段时间前的数据快照(数据库版本),而不管底层数据的当前状态如何。” B 选择更新的行在 A 提交后不存在。相反,有一个 新行 恰好有一些(或全部)相同的值。