【小資說庫】第10期 數據庫事務的隔離性保證機制-事務隔離級別底層的控制機制。

      網友投稿 809 2025-03-31

      上一期我們聊到了事務的臟讀、不可重復讀、幻讀及隔離級別。實現這些隔離級別的底層機制是什么呢?這一期我們來扒一扒。

      并發控制的主要技術有封鎖(locking)(編者注:是指悲觀鎖)、時間戳(timestamp)、樂觀控制法(optimistic sheduler)(編者注:是指樂觀鎖)和多版本并發控制(multi-version concurrency control,MVCC)等。

      封鎖(悲觀鎖)

      鎖的共存關系

      封鎖是實現并發控制的一個非常重要的技術。基本的封鎖類型有兩種:排他鎖(X鎖)和共享鎖(S鎖)。

      排它鎖又稱寫鎖,若事務T1對數據對象A加上X鎖,則只允許T1讀取和修改A,其他任何事務都不能再對A加任何類型的鎖直到T1釋放A上的鎖為止。

      共享鎖又稱讀鎖,若事務T1對數據對象A加上S鎖,則事務T1可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖。

      鎖間的共存關系如下表所示:(x表示是排它鎖(Exclusive),s表示共享鎖(Share),-表示不加鎖。Y表示可以共存,N表示不能共存)

      上圖表示可以共存的鎖,如,第二行表示,一個事務T1給某數據加了X鎖,則事務T2就不能再給那數據加X鎖了,同時也不能再加S鎖了,只有到T1事務提交完成之后,才可以。默認來說,當sql腳本修改更新某條記錄的時候,會給該條記錄加X鎖,讀的話加的是S鎖。

      封鎖協議

      在運用 排他鎖 和 共享鎖 對數據對象加鎖時,還需要約定一些規則,例如何時申請 排他鎖 或 共享鎖、持鎖時間、何時釋放等。稱這些規則為封鎖協議(Locking Protocol)。對封鎖方式規定不同的規則,就形成了各種不同的封鎖協議。不同的封鎖協議對應不同的隔離級別。

      在標準SQL規范中,定義了4個事務隔離級別,不同的隔離級別對事務的處理不同:

      A.?Read uncommited:允許臟讀取,但不允許丟失修改。

      對應一級封鎖協議:事務T在修改數據R之前必須先對其加X鎖,直到事務結束才釋放。事務結束包括正常結束(COMMIT)和非正常結束(ROLLBACK)。

      B.?Read Committed:允許不可重復讀取,但不允許臟讀取和丟失修改。這可以通過“瞬間共享讀鎖”和“排他寫鎖”實現。

      對應二級封鎖協議:一級封鎖協議加上事務T在讀取數據R之前必須先對其加S鎖,讀完后即可釋放S鎖(瞬間S鎖)。

      【小資說庫】第10期 數據庫事務的隔離性保證機制-事務隔離級別底層的控制機制。

      C.?可重復讀取(Repeatable Read):禁止不可重復讀取和臟讀取和丟失修改,但是有時可能出現幻影數據。這可以通過“共享讀鎖”和“排他寫鎖”實現。

      對應三級封鎖協議:一級封鎖協議加上事務T在讀取數據R之前必須先對其加S鎖,直到事務結束才釋放。

      D.?序列化(Serializable):提供嚴格的事務隔離。它要求事務序列化執行,事務只能一個接著一個地執行,但不能并發執行。

      四級封鎖協議是對三級封鎖協議的增強,其實現機制也最為簡單,直接對事務中所讀取或者更改的數據所在的表加表鎖,也就是說,其他事務不能讀寫該表中的任何數據。這樣所有的臟讀,不可重復讀,幻讀,都得以避免!

      活鎖&死鎖

      并發控制會造成活鎖和死鎖。

      活鎖指的是T1封鎖了數據R,T2同時也請求封鎖數據R,T3也請求封鎖數據R,當T1釋放了鎖之后,T3會鎖住R,T4也請求封鎖R,則T2就會一直等待下去。解決這種活鎖等待的處理辦法是采用“先來先服務”策略。

      死鎖就是我等你,你又等我,雙方就會一直等待下去,比如:T1封鎖了數據R1,正請求對R2封鎖,而T2封住了R2,正請求封鎖R1,這樣就會導致死鎖。

      死鎖這種沒有完全解決的方法,只能盡量預防。預防的方法有:①一次封鎖法,指的是一次性把所需要的數據全部封鎖住,但是這樣會擴大了封鎖的范圍,降低系統的并發度;②順序封鎖法,指的是事先對數據對象指定一個封鎖順序,要對數據進行封鎖,只能按照規定的順序來封鎖,但是這個一般不大可能的。

      另外,系統如何判斷出現死鎖呢,畢竟出現死鎖不能一直干等下去,要及時發現死鎖同時盡快解決出現的死鎖,診斷和判斷死鎖有兩種方法,一是超時法,二是等待圖法。超時法就是如果某個事物的等待時間超過指定時限,則判定為出現死鎖;等待圖法指的是如果事務等待圖中出現了回路,則判斷出現了死鎖。對于解決死鎖的方法,只能是撤銷一個處理死鎖代價最小的事務,釋放此事務持有的所有鎖,同時對撤銷的事務所執行的數據修改操作必須加以恢復。

      行級鎖&表級鎖

      最后,說下行級鎖和表級鎖。

      行級鎖是一種排他鎖,防止其他事務修改此行;在使用以下語句時,Oracle會自動應用行級鎖:INSERT、UPDATE、DELETE、SELECT … FOR UPDATE [OF columns] [WAIT n | NOWAIT]; SELECT … FOR UPDATE語句允許用戶一次鎖定多條記錄進行更新 使用COMMIT或ROLLBACK語句釋放鎖

      表級鎖又分為5類:

      行共享 (ROW SHARE) – 禁止其他事務使用排他鎖鎖定表。

      行排他(ROW EXCLUSIVE) – 禁止其他事務使用排他鎖和共享鎖

      共享鎖(SHARE) - 鎖定表,對記錄只讀不寫,多個用戶可以同時在同一個表上應用此鎖。

      共享行排他(SHARE ROW EXCLUSIVE) – 比共享鎖更多的限制,禁止其他事務使用共享鎖及更高的鎖。

      排他(EXCLUSIVE) – 限制最強的表鎖,僅允許其他用戶查詢該表的行。禁止修改和鎖定表。

      以上內容參考自:

      http://blog.sina.com.cn/s/blog_548bd2090100ir7k.html

      https://www.cnblogs.com/ismallboy/p/5574006.html

      樂觀控制法(樂觀鎖)

      https://www.jianshu.com/p/d2ac26ca6525

      https://blog.csdn.net/xlgen157387/article/details/47906553

      上面兩篇帖子對悲觀鎖和樂觀鎖的概念介紹、使用場景及對比介紹的比較全面了,大家可以查閱。

      mysql樂觀鎖和悲觀鎖詳解這篇貼中也通過MySQL的舉例對悲觀鎖和樂觀鎖進行了生動說明,其中有我們比較喜歡的總結信息:

      樂觀鎖,簡單地說,就是從應用系統層面上做并發控制,去加鎖。

      實現樂觀鎖常見的方式:版本號version。

      應用程序在數據表中增加版本號字段,每次對一條數據做更新之前,先查出該條數據的版本號,每次更新數據都會對版本號進行更新。在更新時,把之前查出的版本號跟庫中數據的版本號進行比對,如果相同,則說明該條數據沒有被修改過,執行更新。如果比對的結果是不一致的,則說明該條數據已經被其他人修改過了,則不更新,客戶端進行相應的操作提醒。

      悲觀鎖,簡單地說,就是從數據庫層面上做并發控制,去加鎖。

      悲觀鎖的實現方式有兩種:共享鎖(讀鎖)和排它鎖(寫鎖)

      時間戳

      時間戳就是在數據庫表中單獨加一列時間戳,比如“TimeStamp”,每次讀出來的時候,把該字段也讀出來,當寫回去的時候,把該字段加1,提交之前 ,跟數據庫的該字段比較一次,如果比數據庫的值大的話,就允許保存,否則不允許保存,這種處理方法雖然不使用數據庫系統提供的鎖機制,但是這種方法可以大大提高數據庫處理的并發量,因為這種方法可以避免了長事務中的數據庫加鎖開銷(操作員A 和操作員B操作過程中,都沒有對數據庫數據加鎖),大大提升了大并發量下的系統整體性能表現。

      這樣看來時間戳也是一種樂觀控制法。

      查詢了一些其他博主的博客,也佐證了時間戳是實現樂觀鎖的一種辦法這個觀點。部分博客貼在下面。

      https://blog.csdn.net/crazy_scott/article/details/90452113

      https://blog.csdn.net/sanshi_lxl/article/details/83740635

      https://blog.csdn.net/webdesman/article/details/6360633?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-9.add_param_isCf&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-9.add_param_isCf

      MVCC

      實現數據庫的并發訪問控制,最簡單的方式就是加鎖訪問。由于加鎖會將讀寫操作串行化,所以不會出現不一致的狀態。但是,讀操作會被寫操作阻塞,大幅降低讀性能。MVCC(Multiversion Concurrency Control多版本并發控制)能解決采用鎖帶來的寫操作堵塞讀操作的并發問題。MVCC是通過使用數據的多個版本保證并發讀寫不沖突的一種機制。不同的數據庫會有不同的實現。(參見https://www.jdon.com/repository/database-mvcc.html?)

      MVCC的兩種不同實現方式

      第一種實現方式是將數據記錄的多個版本保存在數據庫中,當這些不同版本數據不再需要時,垃圾收集器回收這些記錄。這個方式被postgresql和Firebird/Interbase采用,SQL Server使用的類似機制,所不同的是舊版本數據不是保存在數據庫中,而保存在不同于主數據庫的另外一個數據庫tempdb中/

      第二種實現方式只在數據庫保存最新版本的數據,但是會在使用undo時動態重構舊版本數據,這種方式被Oracle和MySQL/InnoDB使用。

      有關MySQL和PG的MVCC機制介紹可參考下面的兩篇博客。

      Mysql中MVCC的使用及原理詳解

      postgresql系列_MVCC機制以及鎖機制理解

      總結

      經過上面的多方查閱和梳理,我們可以做如下總結。

      控制數據庫事務并發控制的機制有悲觀控制法和樂觀控制法。

      悲觀控制法對應的是數據庫的鎖機制。悲觀鎖只需要用戶或應用程序設置了DBMS所采用的隔離級別,DBMS后臺就會通過鎖來實現隔離級別,避免臟讀、不可重復讀或幻讀。

      樂觀鎖可以由應用程序通過給數據庫表加version字段或時間戳的方式實現,也可以由數據庫的MVCC機制實現。

      留個疑問在本期,待后續考證:數據庫既支持鎖機制,也支持MVCC機制,那如何設置來選擇這兩種不同的機制呢?

      MySQL 數據庫

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:如何提高你的數據分析技能,掌握Excel表格透視表
      下一篇:如何使用WPS打印文檔?(如何用wps office打印文檔)
      相關文章
      亚洲av无码乱码国产精品fc2| jlzzjlzz亚洲乱熟在线播放| 精品亚洲一区二区| 亚洲日韩国产成网在线观看| 亚洲AV无码成人精品区狼人影院| 99热亚洲色精品国产88| 国产成人精品日本亚洲专| 亚洲欧洲另类春色校园网站| 亚洲中文字幕久在线| 亚洲a级成人片在线观看| 亚洲一卡二卡三卡| 亚洲av无码久久忘忧草| 亚洲国产成人在线视频 | 亚洲福利电影在线观看| 亚洲精品福利网泷泽萝拉| 亚洲成a人片毛片在线| 亚洲成AV人片久久| 亚洲国产精品综合久久20| 亚洲 欧洲 视频 伦小说| 亚洲熟女乱色一区二区三区| 日本亚洲免费无线码 | 亚洲fuli在线观看| 亚洲砖码砖专无区2023| 亚洲第一成年网站视频| 国产亚洲蜜芽精品久久| 亚洲人成人网站在线观看| 久久久久噜噜噜亚洲熟女综合| 亚洲综合av永久无码精品一区二区 | 亚洲 自拍 另类小说综合图区 | 亚洲自偷自偷精品| 亚洲国产美女福利直播秀一区二区| 亚洲成a人片在线观| 亚洲一区AV无码少妇电影| 国产精品亚洲专区无码唯爱网| 在线亚洲v日韩v| 在线观看亚洲成人| 亚洲AV无码成人精品区天堂| 亚洲精品视频免费看| 亚洲偷偷自拍高清| 亚洲成a人片在线观看久| 国产亚洲欧洲精品|