關(guān)于mysql事務(wù)的幾件小事

零.MyISAM和InnoDB關(guān)于鎖的區(qū)別

①M(fèi)yISAM默認(rèn)用的是表級鎖,不支持行級鎖。

②InnoDB默認(rèn)用的是行級鎖,也支持表級鎖。

③共享鎖和排它鎖的兼容性

X 排它鎖 共享鎖
排它鎖 沖突 沖突
共享鎖 沖突 兼容

④使用場景
MyISAM
A: 頻繁執(zhí)行全部count語句。
B: 對數(shù)據(jù)進(jìn)行增刪改的頻率不高,查詢非常頻繁。
C:不需要支持事務(wù)。
InnoDB
A:數(shù)據(jù)增刪改查相當(dāng)頻繁。
B: 要求支持事務(wù)。

一.鎖的分類

按所粒度分:
表級鎖:整個表加鎖
行級鎖:對行數(shù)據(jù)加鎖
頁級鎖: 介入表級個頁級之間的鎖,鎖定位于一個存儲快的相鄰的幾行數(shù)據(jù)。

按鎖級別分:
共享鎖:針對同一份數(shù)據(jù),多個讀操作可以同時進(jìn)行而不會相互影響。
排它鎖: 當(dāng)前寫操作沒有完成前,它會阻止其他寫鎖和讀鎖。

按加鎖方式分
自動鎖:像意向鎖、MyISAM的增刪改查時加的鎖就是自動鎖,這是mysql自動加的鎖。
顯式鎖:像select for update,lock這種我們現(xiàn)實(shí)加的鎖就是顯式鎖。

按操作方式分
DML鎖:對數(shù)據(jù)進(jìn)行操作時加的鎖。
DDL鎖:對表結(jié)構(gòu)進(jìn)行變更加的鎖。

按使用方式分
樂觀鎖:認(rèn)為數(shù)據(jù)不會造成沖突,在提交時才進(jìn)行判斷,不使用數(shù)據(jù)庫的鎖機(jī)制,而是使用版本號或者時間戳實(shí)現(xiàn)。
悲觀鎖:對外界的影響處于保守狀態(tài),在處理中將數(shù)據(jù)鎖定,往往依靠數(shù)據(jù)庫提供的鎖機(jī)制。全程使用排它鎖鎖定,先獲取鎖在執(zhí)行。

三.數(shù)據(jù)庫事務(wù)四大特性

1.原子性
事務(wù)是最小的執(zhí)行單位,不允許分割。事務(wù)的原子性確保動作要么全部完成,要么完全不起作用。
2.一致性
執(zhí)行事務(wù)前后,數(shù)據(jù)保持一致,多個事務(wù)對同一個數(shù)據(jù)讀取的結(jié)果是相同的。
3.隔離性
并發(fā)訪問數(shù)據(jù)庫時,一個用戶的事務(wù)不被其他事務(wù)所干擾,各并發(fā)事務(wù)之間數(shù)據(jù)庫是獨(dú)立的。
4.持久性
一個事務(wù)被提交之后,它對數(shù)據(jù)庫中數(shù)據(jù)的改變是持久性的,即使數(shù)據(jù)庫發(fā)生故障也不應(yīng)該對其有任何影響。

三.并發(fā)事務(wù)帶來的問題

1.臟讀
當(dāng)一個事務(wù)正在訪問數(shù)據(jù)并且對數(shù)據(jù)進(jìn)行修改,而這種修改還沒有提交到數(shù)據(jù)庫中,這時另一個事務(wù)也訪問了這個數(shù)據(jù),然后使用了這個數(shù)據(jù)。因?yàn)檫@個數(shù)據(jù)是還沒有提交的數(shù)據(jù),那么另外一個事務(wù)讀到的這時數(shù)據(jù)是"臟數(shù)據(jù)",依據(jù)"臟數(shù)據(jù)"所做的操作可能是不正確的。
2.丟失修改
指在一個事務(wù)讀取一個數(shù)據(jù)時,另外一個事務(wù)也訪問了這個數(shù)據(jù),那么在第一個事務(wù)中修改了這個數(shù)據(jù)后,第二個事務(wù)也修改了這個數(shù)據(jù)。這樣第一個事務(wù)內(nèi)的修改結(jié)果就會被丟失,稱為丟失數(shù)據(jù)。
3.不可重復(fù)讀
指在一個事務(wù)內(nèi)多次讀同一個數(shù)據(jù)。在這個事務(wù)還沒有結(jié)束時,另一個事務(wù)也訪問了該數(shù)據(jù),那么,在第一個事務(wù)中的兩次讀數(shù)據(jù)之間,由于第二個事務(wù)的修改導(dǎo)致第一個事務(wù)兩次讀取的數(shù)據(jù)可能不太一樣。這就發(fā)生了在一個事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的情況,稱為不可重復(fù)讀。
4.幻讀
幻讀與不可重復(fù)讀類似。它發(fā)生在一個事務(wù)讀取了幾行數(shù)據(jù),接著另一個并發(fā)事務(wù)插入了一些數(shù)據(jù)時。在隨后的的查詢中,第一個事務(wù)就會發(fā)現(xiàn)多了一些原本不存在的記錄,就好像發(fā)生了幻覺一樣,所以稱為幻讀。

四.數(shù)據(jù)庫事務(wù)隔離機(jī)制

1.READ-UNCOMMITTED(讀取未提交)
最低的隔離級別,允許讀取尚未提交的數(shù)據(jù)變更,可能會導(dǎo)致臟讀、幻讀、不可重復(fù)讀。
2.READ-COMMITTED(讀取已提交)
允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù),可以阻止臟讀,但是幻讀和不可重復(fù)讀任有可能發(fā)生。
3.REPEATABLE-READ(可重復(fù)讀)
對同一個字段的多次讀取結(jié)果都是一致的,除非數(shù)據(jù)是被本身事務(wù)自己所修改,可以阻止臟讀和不可重復(fù)做,但幻讀仍有可能發(fā)生。
4.SERIALIZABLE(可串行讀)
最高的隔離級別,完全服從ACID的隔離級別。所有的事務(wù)依次逐個執(zhí)行,這樣的事務(wù)之間就完全不可能產(chǎn)生干擾,也就是說,該級別可以防止臟讀、不可重復(fù)讀以及幻讀。

隔離級別 臟讀 不可重復(fù)讀 幻讀
READ-UNCOMMITTED
READ-COMMITTED ×
REPEATABLE-READ × ×
SERIALIZABLE × × ×

MySQL InnoDB存儲引擎的默認(rèn)支持的隔離級別是REPEATABLE-READ(可重復(fù)讀) ??梢酝ㄟ^@@tx_isolation命令查看。

這里需要注意的是:與SQL標(biāo)準(zhǔn)不同的地方在于InnoDB存儲引擎在REPEATABLE-READ(可重復(fù)讀) 事務(wù)隔離級別下使用的是Next-key Lock算法,因此可以避免幻讀的產(chǎn)生。所以InnoDB存儲引擎的默認(rèn)支持的隔離級別是REPEATABLE-READ(可重復(fù)讀) 已經(jīng)可以完全保證事務(wù)的隔離性要求,即達(dá)到了SQL標(biāo)準(zhǔn)的SERIALIZABLE(可串行化)隔離級別。

因?yàn)楦綦x級別越低,事務(wù)請求的鎖越少,所以大部分?jǐn)?shù)據(jù)庫系統(tǒng)的隔離級別都是READ-COMMITTED;但是InnoDB存儲引擎默認(rèn)使用REPEATABLE-READ 并不會有任何性能損失。
InnoDB存儲引擎在分布式事務(wù)的情況下一般會用到SERIALIZABLE隔離級別。

五.當(dāng)前讀與快照讀

1.當(dāng)前讀

select... lcok in share mode,select.....for update,update,delete,insert等操作都是當(dāng)前讀。

2.快照讀

不加鎖的非阻塞讀,select操作就是快照讀,基于多版本操作。
快照讀的實(shí)現(xiàn):
1.依賴于數(shù)據(jù)行里的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID字段。
DB_TRX_ID:標(biāo)志了最近一次操作這行數(shù)據(jù)的id。
DB_ROLL_PTR:回滾指針,直寫入回滾段的rollback segment的undo日志記錄。
DB_ROW_ID:表示行號,包含一個隨著新行加入單調(diào)自增的記錄(隱藏主鍵)。
2.undo日志
當(dāng)我們對記錄進(jìn)行了變更操作時,就會產(chǎn)生undo日志,undo中記錄的是老版數(shù)據(jù),當(dāng)一個舊的事務(wù)需要讀取記錄時,順著undo鏈就可以讀取到滿足需要的老版本數(shù)據(jù)。分為insert undolog和update undolog,insert undolog只在事務(wù)回滾時被需要,并且在事務(wù)提交之后就可以被丟棄;update undolog會在對數(shù)據(jù)進(jìn)行更新和刪除時產(chǎn)生,不僅在事務(wù)混滾時需要,而且在進(jìn)行快照讀的時候也需要,因此不能隨便刪除。

image.png

3.read view
主要用于做可見性判斷,當(dāng)我去執(zhí)行快照讀select的時候,會針對我們需要讀的數(shù)據(jù)去創(chuàng)建一個read view,決定當(dāng)前能夠讀取到的數(shù)據(jù)是哪個版本;主要基于將數(shù)據(jù)的DB_TRX_ID與當(dāng)前活躍的事務(wù)的ID進(jìn)行對比,如果等于就根據(jù)undolog去取上層的數(shù)據(jù),知道取到比他小的數(shù)據(jù)。

六.RR如何避免幻讀

1.表象:快照讀(非阻塞讀)--偽MVCC
2.內(nèi)在,next-key鎖(行鎖+gap鎖)
GAP鎖
Gap鎖鎖定一個范圍,防止出現(xiàn)幻讀。
1.對主鍵索引或者唯一鎖會有Gap鎖?
如果where條件全部命中,則不會用Gap鎖,只會加行鎖。
2.如果where條件全部不命中,則會用Gap鎖。
3.如果where條件部分命中,則會用Gap鎖。
4.Gap鎖會用在非唯一索引或者不走索引的當(dāng)前讀中。
非唯一索引情況:

非唯一索引.png

如上圖,操作數(shù)據(jù)9,會鎖住(6,9],(9,11]這兩個區(qū)間即(6,11]的區(qū)間會被加上Gap鎖,不被允許操作,這樣就保證了防止幻讀的發(fā)生。gap鎖還要和主鍵值搭配才能精確判斷,比如(6,11]這個區(qū)間被鎖住,但是6對應(yīng)的主鍵是c,如果插入(a,6)這樣的數(shù)據(jù),是可以插入的,但是(d,6)這樣的數(shù)據(jù)就是無法插入的。

不走索引:
不走索引會加表鎖,也就是加全部的Gap鎖,

image.png

七.鎖的建議優(yōu)化

1.盡可能讓所有數(shù)據(jù)檢索都用過索引來完成,避免無索引行鎖升級為表鎖。
2.合理設(shè)計索引,盡量縮小鎖的范圍。
3.盡可能減少檢索條件,避免間隙鎖(Gap鎖)。
4.盡量控制事務(wù)大小,減少鎖定資源量和時間長度。
5.盡可能使用低級別的事務(wù)隔離。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容