postgresql 中明显的事务隔离违规

2024-02-07

我在 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 会来空了。

除了我自己对这些先决条件的完全误解之外,有人能想到我会看到这种行为的另一个原因吗?

不用担心那些糟糕的建筑,它正在消失。我只是想理解为什么这种情况似乎违反了我所理解的“读已提交”事务隔离。

Thanks.


根据 postgres 文档,事务中的一个进程应该 不会“看到”事务中另一个进程所做的更改,直到它们 已承诺。


是和否——像往常一样,这取决于情况。文档 https://www.postgresql.org/docs/current/static/transaction-iso.html严格地说:

已提交读是 PostgreSQL 中的默认隔离级别。

当事务使用此隔离级别时,SELECT 查询 (没有 FOR UPDATE/SHARE 子句) 只看到查询之前提交的数据 开始;它永远不会看到未提交的数据或已提交的更改 在并发事务执行查询期间。实际上,一个 SELECT 查询会看到查询时数据库的快照 开始运行。然而,SELECT 确实看到了之前的效果 更新在其自己的事务中执行,即使它们不是 但已承诺。另请注意,两个连续的 SELECT 命令可以看到 不同的数据,即使它们位于单个事务中,如果 其他事务在第一个 SELECT 开始后提交更改,并且 在第二个 SELECT 开始之前。

更新、删除、选择更新、和 SELECT FOR SHARE 命令 在搜索目标行方面与 SELECT 的行为相同:它们 将仅查找自命令开始时提交的目标行 时间。然而,这样的目标行可能已经被更新(或者 被另一个并发事务删除或锁定) 成立。在这种情况下,潜在的更新程序将等待第一个 更新事务以提交或回滚(如果它仍在 进步)。如果第一个更新程序回滚,那么其影响是 被否定,第二个更新程序可以继续更新 原来找到行。如果第一个更新者提交,第二个更新者提交 如果第一个更新者删除了该行,则将忽略该行,否则会 尝试将其操作应用于该行的更新版本。这 命令的搜索条件(WHERE 子句)被重新评估为 查看该行的更新版本是否仍然与搜索匹配 健康)状况。如果是,则第二个更新器使用以下命令继续其操作 该行的更新版本。对于 SELECT FOR UPDATE 和 SELECT FOR SHARE,这意味着它是该行的更新版本 被锁定并返回给客户端。

换句话说,简单的 SELECT 与 SELECT FOR UPDATE/DELETE/UPDATE 不同。

您可以创建简单的测试用例来观察该行为:

第一节

test=> START TRANSACTION;
START TRANSACTION
test=> SELECT * FROM test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)


test=> DELETE FROM test;
DELETE 10
test=>

现在登录另一个会话 2:

test=> START TRANSACTION;
START TRANSACTION
test=> SELECT * FROM test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)


test=> SELECT * FROM test WHERE x = 5 FOR UPDATE;

最后一条命令之后SELECT ... FOR UPDATE会话 1“挂起”并正在等待某些内容......


回到第 1 节

test=> insert into test select * from generate_series(1,10);
INSERT 0 10
test=> commit;
COMMIT

现在,当您返回到会话 2 时,您将看到以下内容:

test=> SELECT * FROM test WHERE x = 5 FOR UPDATE;
 x
---
(0 rows)


test=> select * from test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)

那就是——简单SELECT仍然没有看到任何变化,同时SELECT ... FOR UPDATE确实看到行已被删除。但它没有看到会话 1 插入的新行

事实上,您看到的序列是:

  • 进程A开始它的事务
  • 进程 A 删除表 T 中的所有内容
  • 进程B开始它的事务
  • 进程 B 尝试对表 T 中的一行进行选择更新
  • 进程 B“挂起”并等待会话 A 进行提交或回滚
  • 进程 A 从传入数据重新填充表 T
  • 进程A提交其事务
  • 进程 B 出现空(会话 A 提交后 0 行)并调用回滚
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

postgresql 中明显的事务隔离违规 的相关文章

  • postgresql-按每个元素中的单词对数组进行排序

    有字符串数组 ARRAY CAT CAT DOG CAT DOG Cat 现在我想根据每个元素中的单词数对该数组进行排序 我已经尝试过 但没有取得任何成功 我想要这个输出 ARRAY CAT DOG CAT DOG CAT Cat 我怎样才
  • 如何从 postgresql 函数或触发器发送一些 http 请求

    我需要通过 http 协议 GET 或 POST 请求 从函数或触发器发送数据 是否可以 您可以尝试用 PL Python 编写触发器并使用 urllib2 进行 POST
  • 实体框架核心事务中的多个 SaveChanges 有什么意义?

    我在 net core 应用程序中使用 EF 我想知道调用之间有什么区别SaveChanges在事务期间多次调用 并且在提交之前仅调用一次 为了更好地说明我的问题 我将提供一些伪代码 public async Task
  • PostgreSQL:比较 json [重复]

    这个问题在这里已经有答案了 众所周知 目前 PostgreSQL 还没有方法来比较两个 json 值 比较就像json json不起作用 但是选角呢json to text before Then select x a y b json t
  • Postgres 平均值计算忽略 null

    这是我的 postgres 表 name revenue John 100 Will 100 Tom 100 Susan 100 Ben 5 rows 在这里 当我计算平均收入时 它返回 100 这显然不是这种情况 而总和 计数 即 400
  • Ubuntu 12.04 上的 DeepDive 安装指南

    在拥有以后很多问题 https stackoverflow com questions 22469188 deepdive installation postgresql error安装深潜项目 http deepdive stanford
  • 为什么我的 postgis 不在几何字段上使用索引?

    Windows 上的 postgresql 9 5 postgis 2 2 我首先创建一个表 CREATE TABLE points id SERIAL ad CHAR 40 name VARCHAR 200 然后 添加一个几何字段 geo
  • Postgresql 串行错误自动增量

    我在 postgresql 上遇到问题 我认为 postgresql 中有一个错误 我错误地实现了一些东西 有一个表包括colmn1 primary key colmn2 unique colmn3 插入一行后 如果我尝试使用现有的另一次插
  • 优化 LATERAL join 中的慢速聚合

    在我的 PostgreSQL 9 6 2 数据库中 我有一个查询 该查询根据一些股票数据构建计算字段表 它为表中的每一行计算 1 到 10 年的移动平均窗口 并将其用于周期性调整 具体来说 CAPE CAPB CAPC CAPS 和 CAP
  • Django 中从 sqlite 迁移到 postgresql

    我想迁移自sqlite to PostgreSQL db 我安装了 postgresql 并在其 shell 上创建数据库 然后配置我的 django 设置如下 default ENGINE django db backends postg
  • 如何计算 Postgres 上图表中所有连接的节点(行)?

    我的桌子有account id and device id One account id可以有多个device ids 反之亦然 我正在尝试计算每个连接的多对多关系的深度 Ex account id device id 1 10 1 11
  • 将 transaction.commit_manually() 升级到 Django > 1.6

    我继承了为 Django 1 4 编写的应用程序的一些代码 我们需要更新代码库以使用 Django 1 7 并最终更新到 1 8 作为下一个长期支持版本 在一些地方它使用旧风格 transaction commit manually and
  • 本地 Postgres 实例和 Azure Cloud Postgres 实例之间的实时同步

    我需要在本地 postgresql 实例与云 postgresql 实例之间设置实时同步过程 请让我知道我可以通过哪些选项来实现它 我是否必须使用任何特定工具或者可以通过复制进行管理 请指教 使用 PgPool http www pgpoo
  • 使用 NLog .NET Core 将日志记录到 PostgreSQL DB

    我尝试将日志记录集成到 NET Core 中的数据库 我能够设置 NLog 并将消息记录到 SQL Server 这很容易 但是当我尝试将 DB 切换到 PostgreSQL 时 似乎没有记录任何内容 以下是startup cs中的代码 p
  • 使用 MacPorts 在 Mac OS X 10.5 上安装 PostgreSQL 时出错

    我已经使用 MacPorts 在几台不同的计算机上安装了 PostgreSQL 没有问题 但是当涉及到我自己的笔记本电脑时 我无法构建它 当我执行此命令时 sudo port install postgresql83 我收到此错误 chec
  • 如何在Django项目中使用PostgreSQL的存储过程或函数

    我正在开发一个 Django 项目 我决定在 PostgreSQL 中编写逻辑代码 而不是用 Python 编写 因此 我在 PostgreSQL 中创建了一个存储过程 例如 存储过程如下所示 create or replace proce
  • 带有可变 WHERE 子句的批量 UPDATE 表

    我有一堆值对 foo1 bar1 foo2 bar2 我想做一堆更新 将 foo 列设置为 foo1 其中 bar 列为 bar1 我正在使用 psycopg2 在 Python 中执行此操作 我可以executemany与查询UPDATE
  • 使用连接池后如何处理过多的并发连接?

    Scenario 假设您有一个拥有大量流量的网站或应用程序 即使使用数据库连接池 性能也会受到真正的打击 站点 应用程序甚至可能崩溃 因为并发连接太多 Question 人们有什么选择来处理这个问题 我的想法 我在想有这个问题的人可以创建多
  • 无法在 Zend Framework 中回滚事务

    我在 Zend Framework 中使用以下代码进行事务 但回滚功能不起作用 数据通过 insertSome data 插入数据库 怎么了 db gt beginTransaction try model gt insertSome da
  • postgresql 不同的不工作

    我使用以下代码从数据库获取值 但是当我编写这段代码时 测试看看问题出在哪里 我注意到查询没有从数据库中获取不同的值 这是查询 select distinct ca id as id acc name as accName pIsu name

随机推荐