最近在网上看到这样一句话Postgres“已提交的而且 xmin 比当前事务的XID小的记录对当前事务才是可见的”。先不评断这句话的正确性;看下这句话的结构,因果关系;
按照此话的意思;要postgres中的数据可见必须满足两个必要条件:
  1. 事务已经提交(commit);
  2. 提交时插入记录的xmin 小于 当前current_txid(事务id)。
而网上对这句话的解释:“这意味着,你可以开始一个新事务然后插入一行记录,直到你提交(COMMIT)之前,你插入的这行记录对其他事务永远都是不可见的。等到提交以后,其他后创建的新事务就可以看到这行新记录了,因为他们满足了 xmin < XID 条件,而且创建哪一行记录的事务也已经完成”。看起来挺合理的,无懈可击似的。接下来我们来推敲推敲。要说记录的可见性;这还得从事务的隔离级别说起。
 
根据《PostgreSQL9.4.4-CN-v1.0.pdf》文档介绍: SQL标准定义了四个级别的事务隔离 { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED }; postgres目前只实现了 {SERIALIZABLE | REPEATABLE READ | READ COMMITTED }这三种。详细大家去看文档;这里不做介绍。
  • 事务隔离级别READ COMMITTED
事务隔离级别:读已提交(READ COMMITTED)这是postgres,greenplum默认的事务隔离级别。若从先事务隔离级别(读已提交)来解释:就是读已经提交的记录;是不是这样呢? 来验证下。
--session A  事务id为1844;
postgres=# begin;
BEGIN
postgres=# select txid_current();
txid_current
--------------
1844 --session B 事务id为1845;并在插入一条记录在lottu05表(未提交)
postgres=# begin;
BEGIN
postgres=# select txid_current();
txid_current
--------------
1845 postgres=# insert into lottu05 values (1001,'lottu');
INSERT 0 1 --在session A/B查看记录; session A读不到记录; session B可以读到记录。
postgres=# select * from lottu05;
id | name
----+------
(0 rows) --在session B提交插入的记录;在查看session A是否可以看到记录。
postgres=# select xmin,* from lottu05;
xmin | id | name
------+------+-------
1845 | 1001 | lottu
--表明session A(当前事务为ID:1844)可以读 插入记录事务id为1845 已经提交的记录。
--总结: 事务隔离级别为读已提交(READ COMMITTED)就是读已经提交的记录。
由此可见,对读已提交隔离级别而言"已提交的而且 xmin’比当前事务的XID小的记录对当前事务才是可见的"是不正确的。
而网上的解释:也是必要不充分条件。那该如何诠释这说话呢?请看下文讲解
是根据当前postgres系统的当前事务ID相比;目前系统下一个事务ID为1846
-- 我们现在看下当前postgres系统 下一个事务id
[postgres@localhost ~]$ pg_controldata |grep NextXID
Latest checkpoint's NextXID: 0/1846
--意思是说这条记录后面开启会话从事务id:1846是可见的。不充分的是事务ID:1844也可以读到该记录。
--然而这句话来源何处;我想是有依据的。接下来我们做一个实验。模拟postgrs穿越到过去。 --session C 现在插入1002-1008条记录;结果如下:
postgres=# select xmin,id,name from lottu05;
xmin | id | name
------+------+---------
1845 | 1001 | lottu
1846 | 1002 | lottu02
1847 | 1003 | lottu03
1848 | 1004 | lottu04
1849 | 1005 | lottu05
1850 | 1006 | lottu06
1851 | 1007 | lottu07
1852 | 1008 | lottu08 --我们现在使用将数据库postgres回到 txid 为1849。注意:该动作不建议操作;
[postgres@localhost ~]$ pg_stop
waiting for server to shut down.......... done
server stopped
[postgres@localhost ~]$ pg_resetxlog -x 1849 $PGDATA
Transaction log reset
[postgres@localhost ~]$ pg_start
server starting
[postgres@localhost ~]$ psql
psql (9.5.0)
Type "help" for help. postgres=# select xmin,id,name from lottu05;
xmin | id | name
------+------+---------
1845 | 1001 | lottu
1846 | 1002 | lottu02
1847 | 1003 | lottu03
1848 | 1004 | lottu04
1849 | 1005 | lottu05
--可以看到上面的xmin:(1850-1852)是不可见的。
--等数据库的事务ID超过1852;这些数据可以展示出来。
postgres=# select txid_current();
txid_current
--------------
1850 postgres=# select txid_current();
txid_current
--------------
1851 postgres=# select txid_current();
txid_current
--------------
1852 postgres=# select xmin,id,name from lottu05;
xmin | id | name
------+------+---------
1845 | 1001 | lottu
1846 | 1002 | lottu02
1847 | 1003 | lottu03
1848 | 1004 | lottu04
1849 | 1005 | lottu05
1850 | 1006 | lottu06
1851 | 1007 | lottu07
1852 | 1008 | lottu08 --从这个实验看来 确实是需要满足网上所说的两个条件。上面也提过;该操作不建议操作。设想;当前时代若可以穿越到历史上各个时代;那历史不乱套了吗?同理如此。
所以说对隔离级别为READ COMMITTED而言;如同它字面解释一样;只要记录COMMITTED;就可以读到。
注意:
--1.该操作不等同 oracle的flashback操作;虽然回到了历史;历史上已经发生的还是会发生。
--2.该操作并不能做数据恢复操作。若对数据做删除进行恢复;可以参考--http://www.cnblogs.com/lottu/p/5761885.html
总结:对隔离级别为READ COMMITTED而言;如同它字面解释一样;只要记录COMMITTED;就可以读到
  • 事务隔离级别:REPEATABLE READ

事务隔离级别:REPEATABLE READ;是不是如同它而言呢?接下来拭目以待吧。

--开启SESSION A; ctid为1857。
postgres=# truncate table lottu05;
TRUNCATE TABLE
postgres=# begin;
BEGIN
postgres=# select txid_current();
txid_current
--------------
1857 --开启session B;隔离级别为REPEATABLE READ。事务id为:1858
postgres=# begin ISOLATION LEVEL REPEATABLE READ;
BEGIN
postgres=# select txid_current();
txid_current
--------------
1858 --在session A插入 10条记录并提交
postgres=# insert into lottu05 select generate_series(1001,1010),'lottu'||generate_series(1,10);
INSERT 0 10
postgres=# commit;
COMMIT --在session B查看是否可以读到记录
postgres=# select * from lottu05;
id | name
----+------
(0 rows) --结果表明session B 读不到 已经提交且 事务ID:1857比session B的事务ID为1858要小的记录。
总结:
对Postgres记录的可见性;网上这句话“已提交的而且 xmin 比当前事务的XID小的记录对当前事务才是可见的”的解释(这意味着,你可以开始一个新事务然后插入一行记录,直到你提交(COMMIT)之前,你插入的这行记录对其他事务永远都是不可见的。等到提交以后,其他后创建的新事务就可以看到这行新记录了,因为他们满足了 xmin < XID 条件,而且创建哪一行记录的事务也已经完成”)是充分不必要;而非充要条件。而这句话的真伪;我相信看到此处的读者应该明白了。
--参考文献

论Postgres的“已提交的而且 xmin’比当前事务的XID小的记录对当前事务才是可见的”的更多相关文章

  1. 本人为巨杉数据库(开源NoSQL)写的C#驱动,支持Linq,全部开源,已提交github

    一.关于NoSQL的项目需求 这些年在做AgileEAS.NET SOA 中间件平台的推广.技术咨询服务过程之中,特别是针对我们最熟悉的医疗行业应用之中,针对大数据分析,大并发性能的需求,我们也在慢慢 ...

  2. SQL Server已提交读快照隔离级别的设置

    如果要把SQL Server数据库事务隔离级别设置为已提交读快照隔离 如果直接运行下面的语句: ALTER Database [mydbname] SET READ_COMMITTED_SNAPSHO ...

  3. git修改已提交记录的注释

    已提交暂存区但还未提交远端仓库 命令:git commit --amend -m 已提交远端仓库 命令:git rebase 可以参考:http://www.cnblogs.com/dudu/p/47 ...

  4. svn命令行修改已提交的版本备注

    svn命令行修改已提交的版本备注 参考文章: stackoverflow.com/questions/304383/how-do-i-edit-a-log-message-that-i-already ...

  5. SQL Server 已提交读快照 测试

    1. 打开数据库 已提交读快照 选项 2. 数据库 已提交读快照 模式下的测试 a) 测试表 Test b) 开启事务1,更新数据C2 = '200'(未提交) BEGIN TRAN ' WHERE ...

  6. TortoiseSVN 忽略文件 忽略已提交文件

    主要以下两种情况: 1.首次提交就做好了忽略拦截:项目首次提交到svn服务器的时候,把该删的删了,然后设置忽略规则,就没问题了. 2.提交一段时间忽然想忽略拦截:经常碰到的,发现设置忽略规则后,没法生 ...

  7. git学习------>如何修改git已提交的记录中的Author和Email?

    一.背景 最近搭建好GitLab后,准备陆陆续续的将之前在SVN仓库中保存的代码迁移到GitLab上,昨天顺利将三个Android组件的代码迁移到GitLab后,其他同事发现迁移是成功了,但是pull ...

  8. Eclipse中使用GIT将已提交到本地的文件上传至远程仓库

    GIT将已提交到本地的文件上传至远程仓库: 1.  右击项目——Team——Push to Upstream,即可将已保存在本地的文件上传推至GIT远程仓库.

  9. 修改GIT已提交的用户名和邮箱

    修改GIT已提交的用户名和邮箱 原文:https://help.github.com/en/github/using-git/changing-author-info 说明 要更改在现有提交中记录的名 ...

随机推荐

  1. js事件冒泡和事件捕获的区别

  2. *HDU 1286,2824欧拉函数

    #include<iostream> #include<string> #include<cstdio> #include<cmath> #includ ...

  3. 类似input框内最右边添加图标,有清空功能

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  4. javascript对象的一点理解

    <script type="text/javascript"> /* js对象:对象的职责是调用属性和调用方法 */ //1.对象的创建的三种方式 var obj = ...

  5. html - 自动播放音乐

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  6. spring-session整合

    如果项目之前没有整合过spring-data-redis的话,这一步需要先做,在maven中添加这两个依赖: <dependency>     <groupId>org.spr ...

  7. 蓝牙物理链路类型:SCO和ACL链路

    蓝牙物理链路ACL(Asynchronous Connectionless), 另外的一种链路是SCO(Synchronous Connection Oriented)主要用来传输对时间要求很高的数据 ...

  8. win8.1蓝屏解决

    按Windows 徽标键 +X键,点击“命令提示符(管理员)”,复制以下命令并运行: SFC /SCANNOW (此命令需要一段时间完成,不要关闭它,即使进度看上去停止不动.) reg add &qu ...

  9. IntelliJ IDEA全文搜索很给力

  10. 在项目里交叉使用Swift和OC【转】

    Swift and Objective-C in the Same Project在项目里交叉使用Swift和OC Swift与OC的兼容性使得你可以在项目里使用Swift+OC的方式编写应用程序,称 ...