2PL(兩階段鎖定)演算法如何工作 -Vlad Mihalcea

banq發表於2019-12-03

2PL(兩階段鎖定)演算法是關聯式資料庫系統用來保證資料完整性的最古老的併發控制機制之一。
在本文中,我將解釋2PL演算法如何工作以及如何以任何程式語言實現它。

鎖型別
在我們開始討論2PL演算法實現之前,解釋讀和寫鎖的工作方式非常重要。
1.讀鎖:讀取或共享鎖定可防止在併發讀取的同時寫入。
2.寫鎖:寫鎖或排他鎖不允許對給定資源進行讀和寫操作。
某些資料庫系統(例如PostgreSQL,MySQL或SQL Server)提供了獲取指定元組或元組範圍上的讀取和寫入鎖的可能性。其他資料庫系統(例如Oracle)僅允許透過FOR UPDATE子句獲取寫/獨佔鎖。

資料庫      Read lock clause        Write lock clause
Oracle      FOR UPDATE            FOR UPDATE
SQL Server   WITH (HOLDLOCK,ROWLOCK)   WITH (HOLDLOCK,UPDLOCK, ROWLOCK)
PostgreSQL   FOR SHARE             FOR UPDATE
MySQL       LOCK IN SHARE MODE      FOR UPDATE


但是,讀和寫鎖不僅限於資料庫系統。傳統上,進入Java synchronized塊允許獲取排他鎖,從1.5版開始,Java允許透過ReentrantReadWriteLock物件進行讀寫鎖。

兩相鎖定/兩段鎖
僅鎖是不足以防止衝突。併發控制策略必須定義如何獲取和釋放鎖,因為這也會影響事務交織。
為此,2PL協議定義了一種鎖定管理策略,以確保嚴格的可序列化性。
2PL協議將事務分為兩部分:

  • 擴充套件階段(獲取鎖,並且不允許釋放鎖)
  • 收縮階段(釋放所有鎖,並且無法進一步獲取其他鎖)。

對於資料庫事務,擴充套件階段意味著允許從事務開始到結束為止獲取鎖,而收縮階段由提交或回滾階段表示,就像在事務結束時一樣,所有已獲取的鎖鎖被釋放。
下圖顯示了2PL如何協調事務交織:

2PL(兩階段鎖定)演算法如何工作 -Vlad Mihalcea

  • 愛麗絲(Alice)和鮑勃(Bob)都post透過SELECT FOR SHARE的PostgreSQL語句獲得了對指定記錄的讀取鎖定。
  • 當Bob嘗試對post條目執行UPDATE語句時,其語句被鎖管理器阻止,因為UPDATE語句需要在該post行上獲取寫鎖,而Alice仍對該資料庫記錄保持讀鎖。
  • 只有在Alice的事務結束並且釋放了所有鎖之後,Bob才能恢復其UPDATE操作。
  • Bob的UPDATE語句將生成鎖升級,因此他先前獲取的讀取鎖將被排他鎖替換,這將防止其他事務獲取同一post記錄上的讀取或寫入鎖。
  • 愛麗絲啟動了一個新事務,併發出了SELECT FOR SHARE針對同一post條目的讀取鎖獲取請求的查詢,但是由於鮑勃對該記錄擁有排他鎖,因此該語句被鎖管理器阻止。
  • 提交Bob的事務後,將釋放他的所有鎖,並且可以恢復Alice的SELECT查詢。


嚴格的可序列化(可序列化、可線性化)
2PL演算法提供嚴格的可序列化性,這是涉及資料完整性的黃金標準。嚴格的可序列化性意味著結果既可序列化又可線性化。
如果兩個或多個事務的關聯讀取和寫入操作以某種結果等效於某種序列執行的方式交錯,則它們是可序列化的。例如,如果我們有兩個事務A和B,只要結果是A,B或B,A,則這兩個事務都是可序列化的。對於N個事務,結果必須等於N!事務排列之一。
但是,可序列性未考慮時間流。另一方面,線性化意味著基於時間的排序。例如,如果任何後續讀取將反映先前寫入操作所做的更改,則系統是可線性化的。有關Lienearizbaility的更多詳細資訊,請檢視本文
 

相關文章