PostgreSQL如何查看事務(wù)所占有的鎖實(shí)操指南
表級鎖命令LOCK TABLE
在PG中,顯式地在表上加鎖的命令為“LOCK TABLE”,此命令的語法如下:
LOCK [TABLE] [ONLY] name [,...][IN lockmode MODE] [NOWAIT]
語法中各項(xiàng)參數(shù)說明如下:
- name:表名
- lockmode:表級鎖模式,即SHARE、EXCLUSIVE、ACCESS SHARE、ACCESS EXCLUSIVE、ROW SHARE、ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE ROW EXCLUSIVE
- NOWAIT:如果沒有NOWAIT這個(gè)關(guān)鍵字,當(dāng)無法獲得鎖時(shí)會一直等待,而如果加了NOWAIT關(guān)鍵字,在無法立即獲取該鎖時(shí),此命令會立即退出并且報(bào)錯
在PG中,事務(wù)自己的鎖是從不沖突的,因此一個(gè)事務(wù)可以在持有SHARE模式的鎖時(shí)再請求ROW EXCLUSIVE鎖,而不會出現(xiàn)自己的鎖阻塞自己的情況。
當(dāng)事務(wù)要更新表中的數(shù)據(jù)時(shí),應(yīng)該申請ROW EXCLUSIVE鎖,而不應(yīng)該申請SHARE鎖,因?yàn)樵诟聰?shù)據(jù)時(shí),事務(wù)還是會對表加ROW EXCLUSIVE鎖,想象一下,在兩個(gè)并發(fā)的事務(wù)都請求SHARE鎖后,開始更新數(shù)據(jù)前要對表加ROW EXCLUSIVE鎖,但由于各自先前已加了SHARE鎖,所以都要等待對方釋放SHARE鎖,因而出現(xiàn)死鎖。從這個(gè)示例可以看出,如果涉及多種鎖模式,那么事務(wù)應(yīng)該總是最先請求最嚴(yán)格的鎖模式,否則就容易出現(xiàn)死鎖。
行級鎖命令
顯式的行級鎖命令是由SELECT命令后加如下子句來構(gòu)成的:
SELECT ... FOR {UPDATE | SHARE} [OF table_name [,...]] [NOWAIT] [...]
- NOWAIT關(guān)鍵字加上,如果無法獲得鎖則直接報(bào)錯,而不會一直等待。
- OF table_name明確指定表名字,那么只有被指定的表會被鎖定,其他在SELECT中使用的表則不會
- 不帶OF table_name的FOR UPDATE或者FOR SHARE子句將鎖定該命令中使用的所有表
- 如果FOR UPDATE或者FOR SHARE應(yīng)用于一個(gè)視圖或者子查詢,那么它將同樣鎖定該視圖或者子查詢中使用到的所有表
- 主查詢中引用了WITH查詢時(shí),WITH查詢中的表并不會被鎖定
- 如果想要鎖定WITH查詢內(nèi)的表行,需要在WITH查詢內(nèi)指定FOR UPDATE或者FOR SHARE關(guān)鍵字
鎖的查看
我們經(jīng)常需要查看一個(gè)事務(wù)產(chǎn)生了哪些鎖,哪個(gè)事務(wù)被哪個(gè)事務(wù)阻塞了,若執(zhí)行一條SQL語句時(shí)阻塞住了,需要查詢?yōu)槭裁醋枞?,是誰阻塞住的,這些信息可以通過查詢系統(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,如果對象是一個(gè)共享對象,不屬于任何數(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),此列的值為列號,這時(shí)classid和objid指向表 | |
virtualtransaction | text | 持有或等待這把鎖的虛擬事務(wù)id | |
pid | integer | 持有或等待這把鎖的服務(wù)進(jìn)程的PID,如果此鎖是被一個(gè)兩階段提交的事務(wù)持有,則此值為NULL | |
mode | text | 鎖的模式名稱,如“ACCESS SHARE”“SHARE”“EXCLUSIVE”等鎖模式 | |
granted | boolean | 如果鎖已被持有,此值為True,如果等待獲得此鎖,則此值為False |
上述中,描述事務(wù)id的字段有三個(gè):
- virtualxid
- transactionid
- virtualtransaction
- transactionid代表事務(wù)id,簡寫為“xid”
- virtualxid代表虛擬事務(wù)id,簡寫為“vxid”
- 每產(chǎn)生一個(gè)事務(wù)id,都會在pg_clog下的commit log文件中占用2bit
- 最早pg中本沒有虛擬事務(wù)id,但是后來發(fā)現(xiàn),有一些事務(wù)根本沒有產(chǎn)生任何實(shí)質(zhì)的變更,如一個(gè)只讀事務(wù)或一個(gè)空事務(wù),若在這種情況下也分配一個(gè)事務(wù)id會造成浪費(fèi),于是提出了虛擬事務(wù)id的概念
- 對于這類只讀事務(wù),值分配一個(gè)虛擬事務(wù)id,而不是實(shí)際分配一個(gè)真實(shí)的事務(wù)id,這樣就不需要在commit log中占用2bit的空間了
pg_locks這張視圖的字段分為以下兩部分:
- virtualtransaction之前的字段(不包括virtualtransaction字段),我們稱其為“第一部分”,用于描述鎖定對象(Locked Object)信息
- virtualtransaction之后的字段(包括virtualtransaction字段),我們稱其為“第二部分”,用于描述持有鎖或等待鎖的session信息
了解上述概念后,可以容易理解virtualxid和virtualtransaction兩個(gè)字段的意思:
- virtualxid在第一部分字段中,表示鎖對象是一個(gè)virtualxid
- virtualtransaction表示持有鎖或等待鎖session的虛擬事務(wù)id
表鎖實(shí)操
1.先開一個(gè)psql窗口,命令如下:
第一個(gè)窗口,查詢PID,并鎖定一張表。
2.第二個(gè)窗口中查看數(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鎖,這是必定會加上的
- 第二行才是我們實(shí)際在表上加的鎖“AccessExclusiveLock”
3.新增一個(gè)窗口,顯示地對表加鎖:
執(zhí)行sql語句發(fā)現(xiàn),該窗口的鎖表語句會被阻塞住
4.查看兩個(gè)進(jìn)程的鎖情況:
- 發(fā)現(xiàn)兩個(gè)進(jìn)程都對表加了鎖
- 進(jìn)程12264中的granted字段為t,說明它獲得了這把鎖
- 進(jìn)程21052中的granted字段為f,說明該進(jìn)程沒有獲得這把鎖,從而被阻塞
行鎖實(shí)操
1.第一個(gè)窗口執(zhí)行如下操作(在加表鎖的基礎(chǔ)上加行鎖):
2.第二個(gè)窗口中查看數(shù)據(jù)庫中的鎖的情況:
行鎖不僅會在表上加意向鎖,也會在相應(yīng)的主鍵上加意向鎖。其中“jxx_test_pkey”就是表的主鍵。
3.另一個(gè)窗口加行鎖:
該窗口阻塞
4.第二個(gè)窗口中查看數(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并不能顯示出每個(gè)行鎖的信息,因?yàn)樾墟i信息并不會被記錄到共享內(nèi)存中。如果記錄到內(nèi)存,意味著對表做全表更新時(shí),表有多少行就需要在內(nèi)存中記錄多少條行鎖信息,那么內(nèi)存會吃不消,所以postgreSQL設(shè)計(jì)成不在內(nèi)存中記錄行鎖信息。
思考:如何獲取進(jìn)程是在哪一行上被阻塞的?
總結(jié)
到此這篇關(guān)于PostgreSQL如何查看事務(wù)所占有的鎖的文章就介紹到這了,更多相關(guān)PostgreSQL查看事務(wù)所占有鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PostgreSQL TIMESTAMP類型 時(shí)間戳操作
這篇文章主要介紹了PostgreSQL TIMESTAMP類型 時(shí)間戳操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12PostgreSQL 實(shí)現(xiàn)將多行合并轉(zhuǎn)為列
這篇文章主要介紹了PostgreSQL 實(shí)現(xiàn)將多行合并轉(zhuǎn)為列的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12PostgreSQL設(shè)置主鍵從1開始自增的詳細(xì)步驟
和MySQL不同,在 PostgreSQL 中,設(shè)置主鍵從1開始自增并重新開始自增是通過序列(sequence)來實(shí)現(xiàn)的,本文給大家分享PostgreSQL設(shè)置主鍵從1開始自增的詳細(xì)步驟,感興趣的朋友一起看看吧2023-11-11PostgreSQL中實(shí)現(xiàn)自增的三種方式舉例
很多小伙伴在把mysql數(shù)據(jù)庫里面的表導(dǎo)入pgsql數(shù)據(jù)庫的時(shí)候,會遇到新增數(shù)據(jù)的時(shí)候id不自增,這篇文章主要給大家介紹了關(guān)于PostgreSQL中實(shí)現(xiàn)自增的三種方式,需要的朋友可以參考下2024-02-02postgresql數(shù)據(jù)庫配置文件postgresql.conf,pg_hba.conf,pg_ident.conf
這篇文章主要為大家介紹了postgresql數(shù)據(jù)庫中三個(gè)重要的配置文件postgresql.conf,pg_hba.conf,pg_ident.conf使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02如何在Neo4j與PostgreSQL間實(shí)現(xiàn)高效數(shù)據(jù)同步
本文詳細(xì)介紹了如何在Neo4j與PostgreSQL兩種數(shù)據(jù)庫之間實(shí)現(xiàn)高效數(shù)據(jù)同步,從基礎(chǔ)概念到全量與增量同步的實(shí)現(xiàn)策略,結(jié)合具體代碼與實(shí)踐案例,為開發(fā)者提供了全面的指導(dǎo),感興趣的朋友跟隨小編一起看看吧2024-12-12Postgresql 賦予用戶權(quán)限和撤銷權(quán)限的實(shí)例
這篇文章主要介紹了Postgresql 賦予用戶權(quán)限和撤銷權(quán)限的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01開源數(shù)據(jù)庫postgreSQL13在麒麟v10sp1源碼安裝過程詳解
這篇文章主要介紹了開源數(shù)據(jù)庫postgreSQL13在麒麟v10sp1源碼安裝過程詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01