postgresql 插入 时间戳_数据也玩躲猫猫?PostgreSQL中别人提交的数据,我为什么看不到?...

073e1f52cbda9fe50ce1cb365e6908ef.gif

原创: Aken DB印象
文章链接:https://mp.weixin.qq.com/s/OkJaWbzcXcJtzSCOFnqeXQ

文章作为DB的学习体会,若有错误欢迎指导。

一、环境介绍

操作系统:CentOS Linux release 7.6.1810 (Core) DB版本:PostgreSQL -11.5 on x86_64-pc-linux-gnu

二、问题描述

同一个实例运行的3个session,在T2时刻session 1向表table01插入一行数据之后,session 2和session 3两个会话执行相同的SQL查询的结果不一样。如下:

096bb9fd46409be0203ff4ca2bef83d4.png


上图中,session 2查到的是2行记录,session 3却只有1条记录。为什么session 2能看到session 1新插入的记录,而session 3却看不到呢?这种情况是在什么场景下发生的呢?

三、相关理论知识回顾

如果有熟悉事务隔离级别的朋友可能已经想到大概的原因。关于事务的隔离级别的介绍,有兴趣的可以查看上一篇文章。

PostgreSQL的事务隔离级别介绍及更改

在说明原因之前,这里先介绍一下PostgreSQL中取名为“transaction snapshot”这个东西,即事务快照。

至于什么是事务快照,以及为什么需要事务快照,我在官方文档中暂时没有看到具体的描述。

下面是个人的理解,不代表官方:

平时我们执行SQL数据读取的时候,实际上读取的是一种状态数据,transaction snapshot本义上指是某个时刻事务的快照,实质代表的是具体时刻具体事务下数据的状态。

既然是状态,那么可能就有当前状态、上一个状态、下一个状态一说。数据库中所说的事务可看作是将数据从上一个状态进入到另一个状态的单位。

这是数据库中的“词典”,理解起来比较干涩,我们可以对应到人类词典中比较容易理解的三个阶段:过去的、当前的、未来的。

所以,我对事务快照的理解为三个阶段:一个transaction snapshot将事务划分为过去的、当前的、未来的三个区域。

比较友好的是,PostgreSQL官方给我们提供了一个获取事务快照的函数:txid_current_snapshot。下面是官网对txid_current_snapshot函数输出结果的原文解析:

Table 9.75. Snapshot Components for PostgreSQL-12

详细介绍见:https://www.postgresql.org/docs/current/functions-info.html

  • xmin,当前处于active状态的最小事务编号;
  • xmax,未来产生的事务中,第一个将被分配的事务编号;
  • xip_list,当前处于active 状态的事务列表(包括in progress和future状态的事务),其余为inactive。

如下,查看当前时刻事务快照:

(postgres@[local]:5432)[akendb01]#select txid_current_snapshot();txid_current_snapshot-----------------------639:642:639,641 <<
  • 1.xmin=639,表示当前时刻快照中最小的是639这个事务。小于该编号的事务都已经终止(提交、回滚或异常终止),这些事务属于“过去的”范围区域。
  • 2.xmax=642,表示将来新事务产生时分配到的第一个事务编号txid,大于等于642的事务未产生,属于“将来的”范围区域。
  • 3.xip_list=(639,641),表示该快照时刻639和641这两个事务正处于active状态,属于“当前的”范围区域。

画成图就是下面这个样子:

485e4ee9f2924373d6297f744ebb0c17.png

transaction snapshot examples

四、原因分析

在PostgreSQL中,提交读(或者叫读提交)read committed事务隔离级别下,session中同一事务的每条SQL执行的时候都会自动去读取当前时刻的事务快照;而在repeatable read级别下,session中同一事务只会在事务开始的第一个SQL获取一次事务快照。

因为read committed级别下,同一事务中不同时刻的SQL获取的快照可能不一样,因此读到的数据可能会不一样。

而repeatable read在整个事务周期只获取一次事务快照,所以同一事务内所有SQL使用的快照都是一致的,因此可以实现重复读,规避了幻读的产生。

pg默认的事务隔离级别transaction isolation为read committed。这是上面文章开头session 2中read committed事务级别下产生幻读的原因,也是session 3中repeatable read可以实现重复读的原因。

请原谅我在文章开头故意将会话的事务隔离级别忽略,目的是为了引导大家可以一起思考。

说到这里,MySQL的朋友可能觉得PostgreSQL中transaction snapshot和MySQL中的一致性视图Read view有点像。

所以,对于文章开头的问题:

  • 1.对于session 2和session 3的结果来说,上述的问题并非因为数据的不一致,而是因为不同的事务隔离级别读取的结果有所区别。
  • 2.对于session 2来说,在同一个事务里面执行相同的查询语句前后得到的结果不一致,这种情况叫幻读。

什么是幻读? 下面是官方的原文解析:

phantom read

A transaction re-executes a query returning a set of rows that satisfy a search condition and finds that the set of rows satisfying the condition has changed due to another recently-committed transaction.

大概意思指:

在一个事务中相同的SQL查询条件前后读取到的结果不一致,原因是后者读取到了其他事务中新提交的数据。

这个问题其实在PostgreSQL-12官方文档中有所提示,pg中repeatable read隔离级别下是不会出现幻读的。如下图标红处所示:

5981df13ec2cb35cc9df2e689ef5822d.png

PostgreSQL-12事务隔离级别

为什么在PostgreSQL中的repeatable read下是Allowed,but not in PG呢?

这正是因为事务快照的作用。下面将文章开始时的例子进行充分的演示。

五、场景演示:提交读、可重复读事务快照对比

下面针对read committed和repeatable read两种事务隔离模式下的事务快照进行对比测试,例子如下:

67085f7bf0d0d283af80f4ed30271011.png

1.T0时间段:

session 1在默认情况下开启事务,txid=666。

session 2在read committed隔离模式下开启事务,txid=674;

session 3在可重复读repeatable read隔离模式下开启事务,txid=675;

session 4开启事务txid=676(略)。

1)事务开始前table01中只有一行记录:tuple 1

(postgres@[local]:5432)[akendb01]#select * from table01; id | name----+-------- 1 | aken01(1 row)(postgres@[local]:5432)[akendb01]#

2)session 1在默认提交读模式下开启事务,事务编号txid=666。

(postgres@[local]:5432)[akendb01]#begin;BEGIN(postgres@[local]:5432)[akendb01]#show default_transaction_isolation; default_transaction_isolation------------------------------- read committed(1 row)(postgres@[local]:5432)[akendb01]#(postgres@[local]:5432)[akendb01]#select txid_current(); txid_current-------------- 666(1 row)(postgres@[local]:5432)[akendb01]#

3)session 2:在提交读隔离级别下开启事务,事务编号txid=674。

(postgres@[local]:5432)[akendb01]#start transaction isolation level read committed;START TRANSACTION(postgres@[local]:5432)[akendb01]#select txid_current(); txid_current-------------- 674(1 row)

4)session 3:在可重复读隔离级别下开启事务,事务编号txid=675

(postgres@[local]:5432)[akendb01]#start transaction isolation level repeatable read;START TRANSACTION(postgres@[local]:5432)[akendb01]#select txid_current(); txid_current-------------- 675(1 row)

5)session 4:分配一个事务txid=676

(postgres@[local]:5432)[akendb01]#select txid_current(); txid_current-------------- 676(1 row)

2.T1时刻,session 1、2、3获取当前事务快照,并读取table01的记录。

1)session 1:读取到的事务快照为'666:676:674,675',读取表的记录数为1行。

(postgres@[local]:5432)[akendb01]#select txid_current_snapshot(); txid_current_snapshot-----------------------666:676:674,675   <<< 实际上txid=676在session 4已经分配,这个和官网将xmax解析为将来产生的第一个事务有矛盾,pg获取事务快照时最后一个txid是否会滞后?(1 row)(postgres@[local]:5432)[akendb01]#(postgres@[local]:5432)[akendb01]#select * from table01;id | name----+--------1 | aken01(1 rows)(postgres@[local]:5432)[akendb01]#

2)session 2:读取到的事务快照为'666:676:666,675',读取表的记录数为1行。

(postgres@[local]:5432)[akendb01]#select txid_current_snapshot(); txid_current_snapshot----------------------- 666:676:666,675(1 row)(postgres@[local]:5432)[akendb01]#(postgres@[local]:5432)[akendb01]#select * from table01;id | name----+--------1 | aken01(1 rows)(postgres@[local]:5432)[akendb01]#

3)session 3:读取到的事务快照为'666:676:666,674',读取表的记录数为1行。

(postgres@[local]:5432)[akendb01]#select txid_current_snapshot(); txid_current_snapshot----------------------- 666:676:666,674(1 row)(postgres@[local]:5432)[akendb01]#(postgres@[local]:5432)[akendb01]#select * from table01;id | name----+--------1 | aken01(1 rows)(postgres@[local]:5432)[akendb01]#

3.T2时刻,session 1往table01插入一行记录并commit提交,session 1、2、3读取table01的记录。

1)session 1在事务txid=666中获取的事务快照为'674:676:674,675',查看结果中可以看到自己新插入的tuple 2。

(postgres@[local]:5432)[akendb01]#insert into table01 values(2,'aken02');INSERT 0 1(postgres@[local]:5432)[akendb01]#commit;COMMITTED(postgres@[local]:5432)[akendb01]#select txid_current_snapshot();txid_current_snapshot-----------------------674:676:674,675 <<< 事务666已提交,session 1事务快照改变,xmin=674(1 row)(postgres@[local]:5432)[akendb01]#select * from table01;id | name----+--------1 | aken012 | aken02(2 rows)(postgres@[local]:5432)[akendb01]#

2)session 2:

session 2在事务txid=674中获取到的快照为'674:676:675'和T1时刻不同,能看到事务txid=666新插入的tuple 2,产生幻读。

(postgres@[local]:5432)[akendb01]#select txid_current_snapshot();txid_current_snapshot-----------------------674:676:675  <<< session 1的事务666

3)session 3:

session 3在事务txid=675中获取的事务快照依旧为'666:676:666,674',和T1时刻的保持一致,看不到事务txid=666新插入的tuple 2,无幻读产生。

(postgres@[local]:5432)[akendb01]#select txid_current_snapshot();txid_current_snapshot-----------------------666:676:666,674  <<

4.T3时间段

session 2、session 3事务结束,session 1、2、3读取到的事务快照都为“676:676:”,且查询结果相同。

(postgres@[local]:5432)[akendb01]#select txid_current_snapshot();txid_current_snapshot-----------------------676:676: <<
71e54298b401251e51524326871d5d10.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/538329.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VMware打卡虚拟机提示“此虚拟机可能已被复制或移动”

“我已移动虚拟机” //表示打开后的虚拟的网卡的mac地址不变&#xff0c;如果复制本地的&#xff0c;同时开机在一个vmnet可能造成冲突。 “我已复制虚拟机” //表示打开后的虚拟机的网卡的物理地址是新生成的&#xff0c;建议不懂的就选这个。 “取消” …

nioqrc oracle,程序停在 readnocancel () from -lib-tls-libpthread.so.0

程序停在 readnocancel () from -lib-tls-libpthread.so.0(2012-04-10 23:20:56)标签&#xff1a;程序杂谈程序停在 __read_nocancel () from /lib/tls/libpthread.so.0我在 IBMBladeCenter JS21机器 (计算机集群)上 利用 MPI C 编程&#xff0c; 但出现了一些奇怪的现象。那就…

synchronized 方法 导致插入数据插不进_synchronized 原理知多少

本文转载于SegmentFault社区作者&#xff1a;ytaosynchronized是 Java 编程中的一个重要的关键字&#xff0c;也是多线程编程中不可或缺的一员。本文就对它的使用和锁的一些重要概念进行分析。使用及原理synchronized 是一个重量级锁&#xff0c;它主要实现同步操作&#xff0c…

SpringMVC源码解析(四)——请求处理

2019独角兽企业重金招聘Python工程师标准>>> 前言 这一篇&#xff0c;将着手介绍一次请求的处理。用到了 HandlerMapping、HandlerAdapter 知识&#xff0c;如果遇到不是太了解&#xff0c;可以回顾下。 源码分析 其实 DispatcherServlet 也只是 Servlet 的一个实现…

求近似数最值_干货|初中数学《数的开方》知识点梳理

本章内容课标的要求● 1.了解平方根、算术平方根、立方根的概念&#xff0c;会用根号表示数的平方根、算术平方根、立方根。● 2.了解乘方与开方互为逆运算&#xff0c;会用平方运算求百以内整数的平方根&#xff0c;会用立方运算会求百以内整数(对应的负整数)的立方根&#xf…

第三章(续)

目录 第二章 灰度变换与空间滤波(续)直方图处理与函数绘图生成直方图直方图均衡直方图匹配空间滤波线性空间滤波非线性空间滤波图像处理工具箱的标准滤波器线性空间滤波器非线性空间滤波器第二章 灰度变换与空间滤波(续) 直方图处理与函数绘图 生成直方图 应用函数 imhist 语法…

Kafka集群安装--测试--关闭

一、前提 1、kafka安装包下载&#xff1a;http://kafka.apache.org/downloads 2、jdk已安装 3、scala已安装 4、zookeeper集群已安装并运行二、步骤 1、对kafka_2.9.2-0.8.1.tgz进行解压缩&#xff1a;tar -zxvf kafka_2.9.2-0.8.1.tgz。2、对kafka目录进行改名&#xff1a;mv …

Java中的工厂模式

设计模式遵循原则 开闭原则&#xff1a;对扩展开放&#xff0c;对修改关闭里氏代换原则&#xff1a;只有当衍生类可以替换掉基类&#xff0c;软件单位的功能不受到影响时&#xff0c;基类才能真正被覆用。而衍生类也能够在基类的基础上增加新的行为依赖倒转原则&#xff1a;开闭…

世界时钟 软件_Clocker for Mac(世界时钟软件)

Clocker for Mac是一款Mac平台上免费的世界时钟工具&#xff0c;方便我们查看世界各地的时间&#xff0c;它是开源免费的&#xff0c;完全没有广告。包括数百个时区&#xff0c;支持24小时制或AM / PM&#xff0c;macz提供Clocker mac免费版&#xff0c;欢迎前来下载&#xff0…

Mac 设置 NDK

2019独角兽企业重金招聘Python工程师标准>>> 1、首先查看我自己的android studio &#xff0c;找到以下路径 如上图&#xff0c;打开一个 AS 项目&#xff0c;file - project structure 这是我的3 个路径 Ndk /Users/dhbm/Library/Android/sdk/ndk-bundle Sdk /User…

Workbench has not been created yet

原因是&#xff1a;加载的插件变更后需要清理 在启动参数最后加入 -clean

四参数拟合曲线_每周放送|曲线拟合

曲线拟合No.1什么是曲线拟合所谓的曲线拟合&#xff0c;就是使用某一个模型(或者称为方程式)&#xff0c;将一系列的数据拟成平滑的曲线&#xff0c;以便观察两组数据之间的内在联系&#xff0c;了解数据之间的变化趋势。No.2曲线拟合的应用在数据分析时&#xff0c;我们有时需…

Spark集群运行jar包程序里的print日志哪里去了?

默认情况下&#xff0c;是输出到stdout里的。 方法一&#xff1a; 进入work所在机器的spark安装目录下的work目录&#xff0c;里面有日志输出。 方法二&#xff1a; 进入spark web ui 里 点击stdout就可以查看&#xff0c;如果没有可能在其他work上。

qt 批量裁剪图片_照片变素描,不用下载App,好用的在线图片处理及图库

我们要处理图片时&#xff0c;无论是在电脑还是手机上&#xff0c;往往都需要下载软件&#xff0c;但如果你只是临时用一下的话&#xff0c;下载软件难免显得工程有点浩大。下面就推荐几个图片处理网站&#xff0c;打开网页就能用。1、图片处理 funny。pho。to这个网站提供了很…

Intellij IDEA15:建立Scala的Maven项目

原文链接&#xff1a;http://blog.csdn.net/silentwolfyh/article/details/51172369 ------------------------------------------------------------------------------------ 在创建Scala的Maven之前要安装JavaJDK 、 Scala 的JDK 、 Maven配置&#xff0c;请参考下面 Int…

linux临时启动进程命令,Linux常用命令(一)服务控制及优化启动过程

Linux常用命令(一)服务控制及优化启动过程一、Red hat系统开机引导过程1、linux操作系统的引导过程一般包括以下几个阶段&#xff1a;开机自检、MBR引导、GRUB菜单、加载Linux内核、init进程初始化。2、Linux系统中的进程使用数字进行标记&#xff0c;每个进程的身份标记号称为…

linux 解决端口占用

2019独角兽企业重金招聘Python工程师标准>>> 1. netstat -apn|grep 9876 2.kill -9 端口号 --------- java 在linux后台运行的命令 ------------- nohup java -jar demo-shiro-0.0.1-SNAPSHOT.jar >temp.txt & 转载于:https://my.oschina.net/likaixuan0/…

IDEA中 @override报错的解决方法

原文路径&#xff1a;http://www.cnblogs.com/printN/p/6870036.html ------------------------------------ 今天用IDEA导入一个java工程时&#xff0c;碰上一个问题&#xff0c;代码中所有override处标红&#xff0c;并提示&#xff1a;override不支持对接口的实现。 网上百…

Linux目录的可写意味着,Linux权限分析 - osc_h5427nyq的个人空间 - OSCHINA - 中文开源技术交流社区...

在学习Linux的权限之前&#xff0c;我们先来理解几个概念:可读&#xff0c;可写 、可执行Linux的文件和目录有以下三种方式&#xff1a;r 、w 、x:可读&#xff0c;可写 、可执行r-可读(read)w-可写(write)x-可执行(execute)所有者 、所属组 、其他人Linux的文件和目录又可以有…

【深度学习篇】--Windows 64下tensorflow-gpu安装到应用

一、前述 一直以为自己的笔记本不支持tensflow-gpu的运行&#xff0c;结果每次运行模型都要好久。偶然间一个想法&#xff0c;想试试自己的笔记本&#xff0c;结果竟然神奇的发现能用GPU。于是分享一下安装步骤. 二、具体 因为版本之间有严格的对应关系&#xff0c;所以本文就将…