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.pswp.cn/news/538329.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/538329.shtml
英文地址,請注明出處:http://en.pswp.cn/news/538329.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

VMware打卡虛擬機提示“此虛擬機可能已被復制或移動”

“我已移動虛擬機” //表示打開后的虛擬的網卡的mac地址不變&#xff0c;如果復制本地的&#xff0c;同時開機在一個vmnet可能造成沖突。 “我已復制虛擬機” //表示打開后的虛擬機的網卡的物理地址是新生成的&#xff0c;建議不懂的就選這個。 “取消” …

埋坑一: vue中子組件調用兄弟組件方法

小計&#xff1a; 開發中遇到子組件需要調用兄弟組件中的方法&#xff0c;如下寫個小demo記錄下心得&#xff0c;如果你有好的方法&#xff0c;請到評論區域指教 父組件示例代碼&#xff1a; 組件功能解析&#xff1a; 通過$emit獲取子組件事件&#xff0c;通過$ref調用子組件中…

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 的一個實現…

oracle中where中使用函數,Oracle 盡量避免在 SQL語句的WHERE子句中使用函數

-- Start在 WHERE 子句中應該盡量避免在列上使用函數&#xff0c;因為這樣做會使該列上的索引失效&#xff0c;影響SQL 語句的性能。即使該列上沒有索引&#xff0c;也應該避免在列上使用函數。考慮下面的情況&#xff1a;CREATE TABLE EMPLOYEE(NAME VARCHAR2(20) NOT NULL,--…

求近似數最值_干貨|初中數學《數的開方》知識點梳理

本章內容課標的要求● 1.了解平方根、算術平方根、立方根的概念&#xff0c;會用根號表示數的平方根、算術平方根、立方根。● 2.了解乘方與開方互為逆運算&#xff0c;會用平方運算求百以內整數的平方根&#xff0c;會用立方運算會求百以內整數(對應的負整數)的立方根&#xf…

第三章(續)

目錄 第二章 灰度變換與空間濾波(續)直方圖處理與函數繪圖生成直方圖直方圖均衡直方圖匹配空間濾波線性空間濾波非線性空間濾波圖像處理工具箱的標準濾波器線性空間濾波器非線性空間濾波器第二章 灰度變換與空間濾波(續) 直方圖處理與函數繪圖 生成直方圖 應用函數 imhist 語法…

Linux Mysql 安裝方法

1、檢查是否有安裝 [rootJDDB mysql]# yum list installed | grep mysql mysql-community-client.x86_64 5.6.39-2.el7 mysql56-community mysql-community-common.x86_64 5.6.39-2.el7 mysql56-community mysql-community…

oracle 經緯度算距離,根據經緯度訣別用java和Oracle存儲過程計算兩點距離

根據經緯度分別用java和Oracle存儲過程計算兩點距離create or replace procedure SP_GET_DISTANCE(cx in number,cy in number,sx in number, sy in number,distance out varchar2)isd number;x number;y number;r number;pi number;begin--開始計算r:6371229;--地球半徑pi:3.1…

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;開閉…

python的底層實現_Python底層封裝實現方法詳解

這篇文章主要介紹了Python底層封裝實現方法詳解,文中通過示例代碼介紹的非常詳細&#xff0c;對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下事實上&#xff0c;python封裝特性的實現純屬“投機取巧”&#xff0c;之所以類對象無法直接調用私有方法和屬性&a…

php 附近的距離,PHP查詢附近的人及其距離的實現方法_PHP

本文實例講述了PHP查詢附近的人及其距離的實現方法。分享給大家供大家參考&#xff0c;具體如下&#xff1a;array(lat>$lat $dlat,lng>$lng-$dlng),right-top>array(lat>$lat $dlat, lng>$lng $dlng),left-bottom>array(lat>$lat - $dlat, lng>$ln…

統計指定目錄下的視頻時長

package time;import java.io.File;import org.apache.log4j.Logger;import it.sauronsoftware.jave.Encoder; import it.sauronsoftware.jave.EncoderException; import it.sauronsoftware.jave.MultimediaInfo;public class Test2 {/* 支持的后綴 */private static final Str…

怎么在cmd中運行python腳本_cmd中運行python腳本智能使用流程

(此時的ScaleMode自動變Vbuser)更有趣的是用來計算字串高、寬的TextHeight/TextWidth也變成以座標0-100的方式來表現了On Error Resume NextSet outstreemWscript.stdoutIf (LCase(Right(Wscript.fullname,11))"Wscript.exe") ThenSet objShellWscript.CreateObject(…

世界時鐘 軟件_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

oracle必須聲明標識符函數,引用變量時需要必須聲明標識符

SQL> declare2 pname emp.ename%type;3 psal emp.sal%type;4 begin5 select enmae,sal into pname,psal from emp where empno7782;6 dbms_output.put_line(pname||xsis||psal);7 end;8 /pname emp.ename%type;*第 2 行出現錯誤:ORA-06550: 第 2 行, 第 7 列:PLS-002…