下面的列表顯示了可用的鎖模式和它們被 postgresql 自動使用的環境。
你也可以用命令 lock 明確獲取這些鎖。
請注意所有這些鎖模式都是表級鎖,即使它們的名字包含單詞 「row」;這些鎖模式的名稱是歷史造成的。
從某種角度而言,這些名字反應了每種鎖模式的典型用法 — 但是語意都是一樣的。
兩種鎖模式之間真正的區別是它們有著不同的衝突鎖集合。
兩個事務在同一時刻不能在同乙個表上持有相互衝突的鎖。
(不過,乙個事務決不會和自身衝突。比如,它可以在乙個表上請求
access exclusive 然後稍後的時候請求 access share。)
非衝突鎖模式可以由許多事務併發地持有。
請特別注意有些鎖模式是自衝突的(比如,在任意時刻 access exclusive 模式就不能夠被多個事務擁有)
而其它地都不是自衝突的(比如,access share 可以被多個事務持有)。
一旦請求到了某種鎖,那麼該鎖模式將持續到事務結束。
表級鎖模式
access share
只與 access exclusive 衝突。
select 和 analyze 命令在被引用的表上請求乙個這種鎖。
通常,任何只讀取表而不修改它的命令都請求這種鎖模式。
row share
與exclusive和access exclusive模式衝突。
select for update 和 select for share
命令在目標表上需要乙個這樣模式的鎖(加上在所有被引用但沒有
for update/for share 的表上的 access share 鎖)。
row exclusive
與 share,share row exclusive,
exclusive 和
access exclusive 模式衝突。
命令 update,delete,
和 insert 自動請求這個鎖模式。
(加上所有其它被引用的表上的 access share 鎖)。
通常,這種鎖將被任何修改表中資料的查詢請求。
share update exclusive
和 share update exclusive,share,
share row exclusive,exclusive,
和 access exclusive 模式衝突。
這個模式保護乙個表不被併發模式改變和 vacuum。
vacuum(不帶 full 選項)請求這樣的鎖。
share
與 row exclusive,share update exclusive,
share row exclusive,exclusive
和 access exclusive 模式衝突。
這個模式避免表的併發資料修改。
create index
語句要求這樣的鎖模式。
share row exclusive
與 row exclusive,
share update exclusive,share,
share row exclusive,exclusive,
和 access exclusive 模式衝突。
任何 postgresql 命令都不會自動請求這樣的鎖模式。
exclusive
與 row share,row exclusive,
share update exclusive,
share,share row exclusive,
exclusive 和 access exclusive
模式衝突。
這個模式只允許併發 access share 鎖,也就是說,
只有對錶的讀動作可以和持有這個鎖模式的事務並行執行。
任何 postgresql 命令都不會在使用者表上自動請求這樣的鎖模式.
不過,在有些操作的時候,會在某些系統表上請求它。
access exclusive
與所有模式衝突。
( access
share, row share, row
exclusive, share update
exclusive, share, share
row exclusive, exclusive, 和
access exclusive).
這個模式保證其所有者(事務)是可以用任意方式訪問該錶的唯一事務。
alter table,
drop table,reindex,cluster和
vacuum full 命令要求這樣的鎖。
在 lock table 命令沒有明確宣告需要的鎖模式時,它也是預設鎖模式。
除了表級鎖以外,還有行級鎖,他們可以是排他的或者是共享的。
特定行上的排他行級鎖是在行被更新的時候自動請求的。
該鎖一直保持到事務提交或者回滾。
行級鎖不影響對資料的查詢;
它們只阻塞對同一行的寫入。
要在不修改某行的前提下請求在該行的乙個排他行級鎖,用 select for update 選取該行。
請注意一旦我們請求了特定的行級鎖,
那麼該事務就可以多次對該行進行更新而不用擔心衝突。
要在一行上請求乙個共享的行級鎖,用 select for share 選取該行。
乙個共享鎖並不阻止其它事務請求同乙個共享的鎖。不過,其它事務不允許更新,刪除,
或者排他鎖住乙個其它事務持有共享鎖的行。任何這麼做的企圖都將被阻塞住,等待共享鎖釋放。
postgresql
不會在記憶體裡儲存任何關於已修改行的資訊,
因此對一次鎖定的行數沒有限制。
不過,鎖住一行會導致一次磁碟寫;因此,象 select for update 將修改選中的行以標記它們被鎖住了,
因此會導致磁碟寫。
除了表級別的和行級別的鎖以外,
頁面級別的共享/排他銷也用於控制對共享緩衝池中表頁面的讀/寫訪問。
這些鎖在抓取或者更新一行後馬上被釋放。
應用程式設計師通常不需要關心頁級鎖,我們在這裡提到它們只是為了完整。
明確鎖定的使用可能會增加死鎖的可能性,
死鎖是是指兩個(或多個)事務相互持有對方期待的鎖。比如,
如果事務 1 在表 a上持有乙個排他鎖,
同時試圖請求乙個在表 b 上的排他鎖,
而事務 2 已經持有表b的排他鎖,而卻正在請求在表 a上的乙個排他鎖,那麼兩個事務就都不能執行。
postgresql 自動偵測到死鎖條件並且會通過退出乙個當事的事務來解決這個問題,
以此來允許其它事務完成。(具體哪個事務會被退出是很難預計的,而且也不應該依靠這樣的預計。)
要注意的是死鎖也可能會因為行級鎖而發生(因此,即使是沒有使用明確的鎖定,也可能發生)。
考慮這樣一種情況,兩個併發事務在修改乙個表。第乙個事務執行了:
update accounts set balance = balance + 100.00 where acctnum = 11111;這樣就在指定帳號的行上請求了乙個行級鎖。然後,第二個事務執行:
update accounts set balance = balance + 100.00 where acctnum = 22222;第乙個 update 語句成功地在指定行上請求到了乙個行級鎖,因此它成功更新了該行。update accounts set balance = balance - 100.00 where acctnum = 11111;
但是第二個 update 語句發現它試圖更新地行已經被鎖住了,
因此它等待持有該鎖的事務結束。事務二現在就在等待事務一結束,然後再繼續執行。
現在,事務一執行:
update accounts set balance = balance - 100.00 where acctnum = 22222;事務一企圖在指定行上請求乙個行級鎖,但是它得不到:事務二已經持有這樣的鎖了。
所以它等待事務二完成。因此,事務一被事務二阻塞住了,而事務二也被事務一阻塞住了:這就是乙個死鎖條件。
postgresql 將偵測這樣的條件並退出其中乙個事務。
防止死鎖的最好方法通常是保證所有使用乙個資料庫的應用都以一致的順序在多個物件上請求鎖定。
在上面的例子裡,如果兩個事務以同樣的順序更新那些行,那麼就不會發生死鎖。
我們也要保證在乙個物件上請求的第乙個鎖是該物件需要的最高的鎖模式。
如果我們無法提前核實這些問題,那麼我們可以通過在現場重新嘗試因死鎖而退出的事務的方法來處理。
只要沒有檢測到死鎖條件,乙個等待表級鎖或者行級鎖的事務將等待衝突鎖的釋放不確定的時間。
這就意味著乙個應用持有開啟的事務時間太長可不是什麼好事情(比如鎖,等待使用者輸入)。
行級鎖和表級鎖
鎖定的範圍不一樣,行級鎖鎖定的是相關的行,別人仍然可以操作該錶的其他行 而表級鎖則鎖定整個表,其他人對該錶的訪問會受到更多的限制。所以,二者的主要區別就是鎖的粒度不一樣,帶來的結果及時併發能力的不同。鎖的粒度越細,併發性越好。行級鎖,一般是指排它鎖,即被鎖定行不可進行修改,刪除,只可以被其他會話se...
MySQL行級鎖 表級鎖
行級鎖 表級鎖的資料不能被其它事務再鎖定,也不被其它事務修改 修改 刪除 是表級鎖時,不管是否查詢到記錄,都會鎖定表 innodb 行鎖是通過給索引上的索引項加鎖 來實現的,這一點mysql與 oracle 不同,後者是通過在資料塊中對相應資料行加鎖來實現的。innodb這種行鎖實現特點意味著 只有...
MySQL行級鎖 表級鎖 頁級鎖
mysql資料庫由於其自身架構的特點,存在多種資料儲存引擎,每種儲存引擎所針對的應用場景特點都不太一樣,為了滿足各自特定應用場景的需求,每種儲存引擎的鎖定機制都是為各自所面對的特定場景而優化設計,所以各儲存引擎的鎖定機制也有較大區別。mysql各儲存引擎使用了三種型別 級別 的鎖定機制 表級鎖定,行...