PostgreSQL如何查看事務(wù)所占有的鎖實操指南
表級鎖命令LOCK TABLE
在PG中,顯式地在表上加鎖的命令為“LOCK TABLE”,此命令的語法如下:
LOCK [TABLE] [ONLY] name [,...][IN lockmode MODE] [NOWAIT]
語法中各項參數(shù)說明如下:
- name:表名
- lockmode:表級鎖模式,即SHARE、EXCLUSIVE、ACCESS SHARE、ACCESS EXCLUSIVE、ROW SHARE、ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE ROW EXCLUSIVE
- NOWAIT:如果沒有NOWAIT這個關(guān)鍵字,當(dāng)無法獲得鎖時會一直等待,而如果加了NOWAIT關(guān)鍵字,在無法立即獲取該鎖時,此命令會立即退出并且報錯
在PG中,事務(wù)自己的鎖是從不沖突的,因此一個事務(wù)可以在持有SHARE模式的鎖時再請求ROW EXCLUSIVE鎖,而不會出現(xiàn)自己的鎖阻塞自己的情況。
當(dāng)事務(wù)要更新表中的數(shù)據(jù)時,應(yīng)該申請ROW EXCLUSIVE鎖,而不應(yīng)該申請SHARE鎖,因為在更新數(shù)據(jù)時,事務(wù)還是會對表加ROW EXCLUSIVE鎖,想象一下,在兩個并發(fā)的事務(wù)都請求SHARE鎖后,開始更新數(shù)據(jù)前要對表加ROW EXCLUSIVE鎖,但由于各自先前已加了SHARE鎖,所以都要等待對方釋放SHARE鎖,因而出現(xiàn)死鎖。從這個示例可以看出,如果涉及多種鎖模式,那么事務(wù)應(yīng)該總是最先請求最嚴(yán)格的鎖模式,否則就容易出現(xiàn)死鎖。
行級鎖命令
顯式的行級鎖命令是由SELECT命令后加如下子句來構(gòu)成的:
SELECT ... FOR {UPDATE | SHARE} [OF table_name [,...]] [NOWAIT] [...]
- NOWAIT關(guān)鍵字加上,如果無法獲得鎖則直接報錯,而不會一直等待。
- OF table_name明確指定表名字,那么只有被指定的表會被鎖定,其他在SELECT中使用的表則不會
- 不帶OF table_name的FOR UPDATE或者FOR SHARE子句將鎖定該命令中使用的所有表
- 如果FOR UPDATE或者FOR SHARE應(yīng)用于一個視圖或者子查詢,那么它將同樣鎖定該視圖或者子查詢中使用到的所有表
- 主查詢中引用了WITH查詢時,WITH查詢中的表并不會被鎖定
- 如果想要鎖定WITH查詢內(nèi)的表行,需要在WITH查詢內(nèi)指定FOR UPDATE或者FOR SHARE關(guān)鍵字
鎖的查看
我們經(jīng)常需要查看一個事務(wù)產(chǎn)生了哪些鎖,哪個事務(wù)被哪個事務(wù)阻塞了,若執(zhí)行一條SQL語句時阻塞住了,需要查詢?yōu)槭裁醋枞钦l阻塞住的,這些信息可以通過查詢系統(tǒng)視圖“pg_locks”來得到。pg_locks視圖中各列的描述如下:
列名稱 | 列類型 | 引用 | 描述 |
---|---|---|---|
locktype | text | 被鎖定的對象類型:relation、extend、page、tuple、transactionid、virtualxid、object、userlock、advisory | |
database | oid | pg_database.oid | 鎖定對象的數(shù)據(jù)庫OID,如果對象是一個共享對象,不屬于任何數(shù)據(jù)庫,此值為“0”,如果對象是“transaction ID”,此值為空 |
relation | oid | pg_class.oid | 如果對象不是表或只是表的一部分,則此值為“NULL”,否則此值是表的OID |
page | integer | 表中的頁號,如果對象不是表行(tuple)或表頁(relation page),則此值為“NULL” | |
tuple | smallint | 頁內(nèi)的行號(tuple) | |
virtualxid | text | 虛擬事務(wù)id | |
transactionid | xid | 事務(wù)id | |
classid | oid | pg_class.oid | 包含該對象系統(tǒng)目錄的id |
objid | oid | any OID column | 對象在系統(tǒng)目錄的oid |
objsubid | smallint | 如果對象是表列(table column),此列的值為列號,這時classid和objid指向表 | |
virtualtransaction | text | 持有或等待這把鎖的虛擬事務(wù)id | |
pid | integer | 持有或等待這把鎖的服務(wù)進(jìn)程的PID,如果此鎖是被一個兩階段提交的事務(wù)持有,則此值為NULL | |
mode | text | 鎖的模式名稱,如“ACCESS SHARE”“SHARE”“EXCLUSIVE”等鎖模式 | |
granted | boolean | 如果鎖已被持有,此值為True,如果等待獲得此鎖,則此值為False |
上述中,描述事務(wù)id的字段有三個:
- virtualxid
- transactionid
- virtualtransaction
- transactionid代表事務(wù)id,簡寫為“xid”
- virtualxid代表虛擬事務(wù)id,簡寫為“vxid”
- 每產(chǎn)生一個事務(wù)id,都會在pg_clog下的commit log文件中占用2bit
- 最早pg中本沒有虛擬事務(wù)id,但是后來發(fā)現(xiàn),有一些事務(wù)根本沒有產(chǎn)生任何實質(zhì)的變更,如一個只讀事務(wù)或一個空事務(wù),若在這種情況下也分配一個事務(wù)id會造成浪費(fèi),于是提出了虛擬事務(wù)id的概念
- 對于這類只讀事務(wù),值分配一個虛擬事務(wù)id,而不是實際分配一個真實的事務(wù)id,這樣就不需要在commit log中占用2bit的空間了
pg_locks這張視圖的字段分為以下兩部分:
- virtualtransaction之前的字段(不包括virtualtransaction字段),我們稱其為“第一部分”,用于描述鎖定對象(Locked Object)信息
- virtualtransaction之后的字段(包括virtualtransaction字段),我們稱其為“第二部分”,用于描述持有鎖或等待鎖的session信息
了解上述概念后,可以容易理解virtualxid和virtualtransaction兩個字段的意思:
- virtualxid在第一部分字段中,表示鎖對象是一個virtualxid
- virtualtransaction表示持有鎖或等待鎖session的虛擬事務(wù)id
表鎖實操
1.先開一個psql窗口,命令如下:
第一個窗口,查詢PID,并鎖定一張表。
2.第二個窗口中查看數(shù)據(jù)庫中的鎖的情況:
sql命令:
select locktype,relation::regclass as rel,virtualxid as vxid,transactionid as xid,virtualtransaction as vxid2,pid,mode,granted from pg_locks where pid = 12264;
通過上述圖片可以看出:
- 第一行顯示的是事務(wù)在自己的“virtualxid”上加的ExclusiveLock鎖,這是必定會加上的
- 第二行才是我們實際在表上加的鎖“AccessExclusiveLock”
3.新增一個窗口,顯示地對表加鎖:
執(zhí)行sql語句發(fā)現(xiàn),該窗口的鎖表語句會被阻塞住
4.查看兩個進(jìn)程的鎖情況:
- 發(fā)現(xiàn)兩個進(jìn)程都對表加了鎖
- 進(jìn)程12264中的granted字段為t,說明它獲得了這把鎖
- 進(jìn)程21052中的granted字段為f,說明該進(jìn)程沒有獲得這把鎖,從而被阻塞
行鎖實操
1.第一個窗口執(zhí)行如下操作(在加表鎖的基礎(chǔ)上加行鎖):
2.第二個窗口中查看數(shù)據(jù)庫中的鎖的情況:
行鎖不僅會在表上加意向鎖,也會在相應(yīng)的主鍵上加意向鎖。其中“jxx_test_pkey”就是表的主鍵。
3.另一個窗口加行鎖:
該窗口阻塞
4.第二個窗口中查看數(shù)據(jù)庫中的鎖的情況:
xid為739的鎖被進(jìn)程12264持有了,所以21052的進(jìn)程獲取鎖標(biāo)識為False
5.如何查看具體是哪一行數(shù)據(jù)被阻塞
-- 其中0和1分別代表pg_locks中的page和tuple字段 select * from jxx_test where ctid = '(0,1)'
pg_locks并不能顯示出每個行鎖的信息,因為行鎖信息并不會被記錄到共享內(nèi)存中。如果記錄到內(nèi)存,意味著對表做全表更新時,表有多少行就需要在內(nèi)存中記錄多少條行鎖信息,那么內(nèi)存會吃不消,所以postgreSQL設(shè)計成不在內(nèi)存中記錄行鎖信息。
思考:如何獲取進(jìn)程是在哪一行上被阻塞的?
總結(jié)
到此這篇關(guān)于PostgreSQL如何查看事務(wù)所占有的鎖的文章就介紹到這了,更多相關(guān)PostgreSQL查看事務(wù)所占有鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- PostgreSQL 存儲過程的進(jìn)階講解(含游標(biāo)、錯誤處理、自定義函數(shù)、事務(wù))
- PostgreSQL長事務(wù)與失效的索引查詢淺析介紹
- PostgreSQL長事務(wù)概念解析
- PostgreSQL數(shù)據(jù)庫事務(wù)插入刪除及更新操作示例
- PostgreSQL事務(wù)回卷實戰(zhàn)案例詳析
- 基于Postgresql 事務(wù)的提交與回滾解析
- PostgreSQL數(shù)據(jù)庫事務(wù)實現(xiàn)方法分析
- PostgreSQL數(shù)據(jù)庫事務(wù)出現(xiàn)未知狀態(tài)的處理方法
- 深入理解PostgreSQL 事務(wù)處理
相關(guān)文章
免密使用PostgreSQL數(shù)據(jù)庫內(nèi)置工具的兩種方法
我們在PostgreSQL數(shù)據(jù)庫自帶的各種工具時,每次使用都要輸入數(shù)據(jù)庫密碼,這里我們通過配置的方式,以后再使用這些工具就不需要輸入數(shù)據(jù)庫密碼了,需要的朋友可以參考下2025-03-03解決PostgreSQL服務(wù)啟動后占用100% CPU卡死的問題
前文書說到,今天耗費(fèi)了九牛二虎之力,終于馴服了NTFS權(quán)限安裝好了PostgreSQL,卻不曾想,服務(wù)啟動后,新的狀況又出現(xiàn)了。2009-08-08PostgreSQL?16?新特性之正態(tài)分布隨機(jī)數(shù)函數(shù)的示例
這篇文章主要介紹了PostgreSQL?16?新特性之正態(tài)分布隨機(jī)數(shù)函數(shù),PostgreSQL 16 新增了一個內(nèi)置的 random_normal() 函數(shù),用于生成這種隨機(jī)數(shù),通過示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01PostgreSQL的upsert實例操作(insert on conflict do)
這篇文章主要介紹了PostgreSQL的upsert實例操作(insert on conflict do),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01PostgreSQL物理備份恢復(fù)之 pg_rman的用法說明
這篇文章主要介紹了PostgreSQL物理備份恢復(fù)之 pg_rman的用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02PostgreSQL 實現(xiàn)給查詢列表增加序號操作
這篇文章主要介紹了PostgreSQL 實現(xiàn)給查詢列表增加序號操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01