firebird 行级锁问题_MySQL 锁
數(shù)據(jù)庫系統(tǒng)使用鎖是為了支持對共享資源進行并發(fā)訪問,保障數(shù)據(jù)的完整性和一致性。
鎖設(shè)計
不同存儲引擎的鎖設(shè)計是不一樣的,InnoDB 存儲引擎會在行級對數(shù)據(jù)上鎖,不過 InnoDB 存儲引擎也會在數(shù)據(jù)庫內(nèi)部其他多個地方使用鎖。例如,操作緩存池中的LRU列表,刪除、添加、移動LRU列表中的元素,為了保持一致性,必須有鎖的介入。MyISAM 存儲引擎中鎖是表鎖設(shè)計,在并發(fā)讀沒啥問題,但是相比行鎖并發(fā)寫的性能就差了很多。
InnoDB 存儲引擎中的鎖
InnoDB 存儲引擎實現(xiàn)了兩種標(biāo)準(zhǔn)的行級鎖:
共享鎖(S Lock):允許事務(wù)讀一行數(shù)據(jù)
排他鎖(X Lock):允許事務(wù)刪除或更新一行數(shù)據(jù)
如果一個事務(wù) T1 已經(jīng)獲取了行 r 的共享鎖,那么另外的事務(wù) T2 也可以獲得行 r 的共享鎖,稱鎖兼容,因為讀共享,并沒有改變數(shù)據(jù)。但如果其他事務(wù) T3 想獲取行 r 的排他鎖,則必須等待事務(wù) T1 和 T2 釋放行 r 上的共享鎖,稱鎖不兼容。下表顯示了共享鎖和排他鎖的兼容性:
| X | 不兼容 | 不兼容 |
| S | 不兼容 | 兼容 |
InnoDB 存儲引擎支持多粒度鎖定,這種鎖定允許事務(wù)在行級上的鎖和表級上的鎖同時存在,為了支持多粒度上加鎖 InnoDB 存儲引擎支持一種額外加鎖方式,稱之為意向鎖。若將上鎖的對象當(dāng)作有層級的樹圖來看,如果想對最細(xì)粒度上鎖就需要先對粗粒度上鎖。如下圖中,如果想對記錄 r 上 X 鎖,那么需要分別對數(shù)據(jù)庫 A、表、頁上意向 IX 鎖,最后才能對記錄 r 上 X 鎖。
意向鎖是將鎖定的對象分為多個層次,意向鎖意味著事務(wù)希望在更細(xì)粒度上進行加鎖。意向鎖的設(shè)計比較簡練,其意向鎖即為表級鎖,目的主要為了在一個事務(wù)中揭示下一行將被請求的鎖類型。其支持兩種意向鎖:
意向共享鎖(IS Lock):事務(wù)想要獲得一張表中的某些行數(shù)據(jù)的共享鎖
意向排他鎖(IX Lock):事務(wù)想要獲得一張表中的某些行數(shù)據(jù)的排他鎖 由于 InnoDB 存儲引擎支持的是行級的鎖,因此意向鎖并不會阻塞除全部掃以外的任何請求。表級意向鎖和行級鎖的兼容性如下表:
| IS | 兼容 | 兼容 | 兼容 | 不兼容 |
| IX | 兼容 | 兼容 | 不兼容 | 不兼容 |
| S | 兼容 | 不兼容 | 兼容 | 不兼容 |
| X | 不兼容 | 不兼容 | 不兼容 | 不兼容 |
向一個表添加表級 X 鎖的時候(執(zhí)行 ALTER TABLE, DROP TABLE, LOCK TABLES 等操作),如果沒有意向鎖的話,則需要遍歷所有整個表判斷是否有行鎖的存在,以免發(fā)生沖突。如果有了意向鎖,只需要判斷該意向鎖與即將添加的表級鎖是否兼容即可。因為意向鎖的存在代表了,有行級鎖的存在或者即將有行級鎖的存在,因而無需遍歷整個表,即可獲取結(jié)果。
鎖狀態(tài)
在 InnoDB 1.0 版本之前,用戶可以通過?SHOW ENGINE INNODB STATUS?命令查看當(dāng)前鎖請求的信息。從 InnoDB 1.0 版本開始,在 INFORMATION_SCHEMA 架構(gòu)下添加了表 INNODB_TRX、INNODB_LOCKS、INNODB_LOCK_WAITS 三張表,用戶可以更簡單地監(jiān)控當(dāng)前事務(wù)和鎖狀態(tài)。表結(jié)構(gòu)如下:
鎖的算法
InnoDB 存儲引擎由三種行鎖算法,如下:
Record Lock:單行記錄鎖
Gap Lock:間隙鎖,鎖定一定范圍,不包含記錄本身
Next-Key Lock:鎖定一定范圍并且包含記錄本身
Next-Key Lock 是結(jié)合 Record Lock 和 Gap Lock 的一種鎖算法,在 Next-Key Lock 算法下,InnoDB 存儲引擎對于行的查詢都采用的是這種鎖定方式。例如一個索引有 10、11、13 和 20 這四個值,那么該索引可能被 Next-Key Locking 的區(qū)間為:(-∞,10]、(10,11]、(11,13]、(13,20]、(20,+∞)。當(dāng)查詢的索引是唯一鍵(單列唯一),InnoDB 存儲引擎會對 Next-Key Lock 進行優(yōu)化降級為 Record Lock,僅需要鎖住本身即可。
Next-Key Lock 鎖算法解決了幻讀問題。幻讀問題是指在同一個事務(wù)下,連續(xù)執(zhí)行兩次同樣的 SQL 語句可能返回不同的結(jié)果,第二次的 SQL語句可能返回之前不存在的行。通過 Next-Key Lock 算法,即使用戶通過索引查詢一個不存在的值,其鎖定的也是一個范圍,另一個事務(wù)的操作是不會執(zhí)行的,這樣便避免了幻讀。
阻塞
鎖等待就帶來了阻塞,在 InnoDB 存儲引擎中參數(shù)?innodb_lock_wait_timeout?用來控制等待時間,參數(shù)?innodb_rollback_on_timeout?用來設(shè)置等待超時事務(wù)是否回滾。
死鎖
死鎖是指兩個或兩個以上的事務(wù)在執(zhí)行過程中,因資源競爭而造成的互相等待的現(xiàn)象。
死鎖的四個必要條件:
互斥條件:一個資源每次只能被一個進程使用。
占有且等待:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
不可強行占有:進程已獲得的資源,在末使用完之前,不能強行剝奪。
循環(huán)等待條件:若干進程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
若無外力作用事務(wù)將無法推進,解決死鎖問題最簡單的方法就是超時,即當(dāng)兩個事務(wù)死鎖,當(dāng)一個事務(wù)達(dá)到等待閾值回滾,另一個事務(wù)繼續(xù)執(zhí)行。超時機制簡單,但如果超時的事務(wù)很大很重,回滾的代價會很大。除了超時機制,InnoDB 存儲引擎還提供了 wait-for graph(等待圖) 的方式進行死鎖檢測。
wait-for graph? 要求數(shù)據(jù)庫保存鎖的信息鏈路和事務(wù)等待鏈路,通過它們構(gòu)造出一張圖,而這張圖中若存在回路就代表死鎖,因為資源間發(fā)生了相互等待。wait-for graph 是主動的死鎖檢測機制,在每個事務(wù)請求鎖并發(fā)生等待時都會判斷是否存在回路,如果存在死鎖 InnoDB 存儲引擎通常選擇回滾 undo 量最小的事務(wù),從而減少性能損耗。
鎖升級
鎖升級是指粗化當(dāng)前鎖的粒度,如把 1000 個行鎖升級為一個頁鎖。InnoDB 存儲引擎中不存在鎖升級,這是因為 InnoDB 存儲引擎不是通過行記錄產(chǎn)生行鎖的,而是通過每個事務(wù)訪問的每個頁通過位圖對鎖進行管理,因此一個事務(wù)不管是鎖住一個頁的一條記錄還是多條記錄,開銷通常是一致的。
公眾號文章同步github。
本文地址:github.com/lazecoding/Note/blob/main/note/articles/mysql/鎖.MD
總結(jié)
以上是生活随笔為你收集整理的firebird 行级锁问题_MySQL 锁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 页面加载成功后调用_在微信小程序里实现图
- 下一篇: ue4sky时间_UE4 SkyLigh