PostgreSQL只读事务导致可串行化失败一例

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核8GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介: PostgreSQL的手册中有一段讲可串行化的,大意是可串行化事务读到的数据未必是可靠的,除非它提交成功了。 http://postgres.cn/docs/9.3/transaction-iso.html#XACT-SERIALIZABLE -----------------------------------------------------------------------------------------当依赖于可串行化事务阻止异常现象时,来自永久用户表读取的任何数据,直到读取它的事务成功提交为止,都不被认为是有效的。
PostgreSQL的手册中有一段讲可串行化的,大意是 可串行化事务读到的数据未必是可靠的,除非它提交成功了。

http://postgres.cn/docs/9.3/transaction-iso.html#XACT-SERIALIZABLE
-----------------------------------------------------------------------------------------
当依赖于可串行化事务阻止异常现象时,来自永久用户表读取的任何数据,直到读取它的事务成功提交为止,都不被认为是有效的。 这即使对于只读事务也是对的,除了在 可延期的 只读事务中,数据在读到它的时候就是有效的。 因为这样一个事务将一直等到可以获得一个保证不会受此类问题困扰的快照的时候,才开始读取数据。 在所有其他情况下,应用不能依赖于事务期间读到的结果,这个事务之后可能会被终止;取而代之的是,它们应该重试事务直到成功为止。
-----------------------------------------------------------------------------------------

但是,对一个只读的 可串行化 事务,我没有找到任何系统会将其终止的案例(也许有),但是很容易可以找到由于 只读可串行化事务的出现,使得原本可以成功的写事务失败了。这应该也比较好理解,对与一个 只读的事务,终止它有什么意义呢?该读的和不该读的数据它都已经读到了,只能迁就它,其它写事务失败了。下面是个例子

例子1: 2个读写事务不发生冲突
会话(事务)A

  1. postgres=# begin transaction isolation level serializable;
  2. BEGIN
  3. postgres=# select * from tb1;
  4.  id | name
  5. ----+------
  6. (0 rows)

  7. postgres=# insert into tb1 values(1,'a');
  8. INSERT 0 1

会话(事务)B
  1. postgres=# begin transaction isolation level serializable;
  2. BEGIN
  3. postgres=# insert into tb1 values(1,'b');
  4. INSERT 0 1
  5. postgres=# commit;
  6. COMMIT

会话(事务)A
  1. postgres=# commit;
  2. COMMIT

虽然,事务B先提交的,但逻辑上,事务A被排在了事务B前面,因为事务A没有看到事务B提交的修改,这就是所谓的rw依赖。

例子2: 2个读写事务+1个只读事务导致并发冲突
如果在例子1的两个事务之外在插入一个只读的事务C,可能就会使A,B,C之间的依赖关系形成环路,而不得不终止掉一个事务。

会话(事务)A
  1. postgres=# begin transaction isolation level serializable;
  2. BEGIN
  3. postgres=# select * from tb1;
  4.  id | name 
  5. ----+------
  6. (rows)

  7. postgres=# insert into tb1 values(1,'a');
  8. INSERT 0 1

会话(事务)B
  1. postgres=# begin transaction isolation level serializable;
  2. BEGIN
  3. postgres=# insert into tb1 values(1,'b');
  4. INSERT 0 1
  5. postgres=# commit;
  6. COMMIT

会话(事务)C
  1. postgres=# begin transaction isolation level serializable read only;
  2. BEGIN
  3. postgres=# select * from tb1;
  4.  id | name
  5. ----+------
  6.   1 | b
  7. (1 row)

  8. postgres=# commit; --这里不忙提交,让事务A先提交结果也是一样的。
  9. COMMIT

会话(事务)A
  1. postgres=# commit;
  2. ERROR: could not serialize access due to read/write dependencies among transactions
  3. DETAIL: Reason code: Canceled on identification as a pivot, during commit attempt.
  4. HINT: The transaction might succeed if retried.
例子2中,事务C读到了事务B已提交的数据,所以应该在B之后(即wr依赖); 事务C没有读到事务A未提交的修改,所以应该在事务A之前(即rw依赖);而根据例1,事务A又应该在事务B之前。这就形成了环路,也就是冲突。

参考
src/backend/storage/lmgr/README-SSI
http://postgres.cn/docs/9.3/transaction-iso.html#XACT-SERIALIZABLE
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
SQL 缓存 运维
PostgreSQL 事务号回卷分析
## XID 定义 xid 是个啥东西?xid 就是 PostgreSQL 里面的事务号,每个事物都会分配一个 xid。PostgreSQL 数据中每个元组头部都会保存着 插入 或者 删除 这条元组的事务号,即 xid,然后内核通过这个 xid 进行元组的可见性判断。简单理解,比如有两个事务,xid1=200,xid2=201,那么 xid1 中只能看到 t_xmin 200 的元组。 ```c
|
存储 SQL Oracle
02-PostgreSQL 存储过程的进阶介绍(含游标、错误处理、自定义函数、事务)
02-PostgreSQL 存储过程的进阶介绍(含游标、错误处理、自定义函数、事务)
|
Oracle 关系型数据库 数据库
PostgreSQL技术大讲堂 - 第20讲:事务概述与隔离级别
PostgreSQL从小白到专家,技术大讲堂 - 第20讲:事务概述与隔离级别
347 2
|
关系型数据库 PostgreSQL
PostgreSQL事务提交日志与CLOG操作初步认识
PostgreSQL事务提交日志与CLOG操作初步认识
416 0
|
SQL 存储 Oracle
PostgreSQL 事务隔离级别的实现和多版本并发控制|学习笔记
快速学习 PostgreSQL 事务隔离级别的实现和多版本并发控制
PostgreSQL 事务隔离级别的实现和多版本并发控制|学习笔记
|
SQL Oracle 关系型数据库
Oracle/Mysql迁移到Postgresql事务回滚行为差异(开发避坑系列)
Mysql或Oracle迁移到Postgresql系产品后,经常会发生事务回滚导致的问题,具体问题一般都是类似于: **为什么我没rollback,我的事务就自己回滚了?** 下面我举一个简单的例子,说明下PG和其他两款DB在事务回滚行为上的差异 ## Oracle事务内报错后的行为 (完整代码贴在文章最后) ```java Class.fo
1191 0
|
SQL 关系型数据库 数据库
PostgreSQL TRANSACTION(事务)
TRANSACTION(事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。 数据库事务通常包含了一个序列的对数据库的读/写操作。包含有以下两个目的: 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。 当事务被提交给了数据库管理系统(DBMS),则 DBMS 需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要回滚,回到事务执行前的
248 0
|
存储 SQL 关系型数据库
【学习资料】第16期快速入门PostgreSQL应用开发与管理 - 6 事务和锁
大家好,这里是快速入门PostgreSQL应用开发与管理 - 6 事务和锁
|
SQL 关系型数据库 PostgreSQL
AnalyticDB for PostgreSQL 6.0新特性解析 - OLTP 高并发事务能力优化
本文介绍 ADB PG6.0版本里,面向 OLTP 的高并发执行优化
4475 0

推荐镜像

更多