一文帶你了解資料庫隔離級別和鎖之間的聯絡

2021-10-14 16:07:01 字數 4000 閱讀 2964

在具體聊之前,咱先記住一句話: 資料庫事務有不同的隔離級別,不同的隔離級別對鎖的使用是不同的,鎖的應用最終導致不同事務的隔離級別。

首先程式是可以併發執行的,同樣,在mysql中,乙個表可以由兩個或多個程序同時來讀寫資料,這是沒有問題的。

比如,此時有兩個程序來讀資料,這也沒什麼問題,允許。但是如果乙個程序在讀某一行的資料的過程中,另乙個在程序又往這一行裡面寫資料(改、刪),那結果會是如何?

同樣,如果兩個程序都同時對某一行資料進行更改,以誰的更改為準?那結果又會怎樣,不敢想象,是不是資料就被破壞掉了。所以此時是衝突的。

既然會衝突就要想辦法解決,靠誰來解決,這時候就是靠鎖機制來維護了。怎麼使用鎖來使它們不衝突呢?

在事務開始的時候可以給要準備寫操作的這一行資料加乙個排它鎖,如果是讀操作,就給該行資料乙個讀鎖。這樣之後,在修改該行資料的時候,不讓其他程序對該行資料有任何操作。

而讀該行資料的時候,其他程序不能更改,但可以讀。讀或寫完成時,釋放鎖,最後commit提交。這時候讀寫就分離開了,寫和寫也就分離開了。

mysql開發者給這個解決衝突的方案起了乙個名字叫做:讀未提交:(read uncommitted)。這也就是事務的第乙個隔離性。

注意:上面的加鎖和釋放鎖的過程由mysql資料庫自身來維護,不需要我們人為干涉

1、a修改事務級別為:未提交讀。並開始事務,對user表做一次查詢:

2、b事務更新一條記錄:

3、此時b事務還未提交,a在事務內做一次查詢,發現查詢結果已經改變:

4、b進行事務回滾:

5、a再做一次查詢,查詢結果又變回去了:

由試驗得知:在乙個程序的事務當中,我更改了其中的一行資料,但是我修改完之後就釋放了鎖,這時候另乙個程序讀取了該資料,此時先前的事務是還未提交的,直到我回滾了資料,另乙個程序讀的資料就變成了無用的或者是錯誤的資料。

我們通常把這種資料叫做髒資料,這種情況讀出來的資料叫做賍讀

怎麼辦呢?當然還是靠鎖機制。

無非是鎖的位置不同而已,之前是只要操作完該資料就立馬釋放掉鎖,現在是把釋放鎖的位置調整到事務提交之後,此時在事務提交前,其他程序是無法對該行資料進行讀取的,包括任何操作。

那麼資料庫為此種狀態的資料庫操作規則又給了乙個名字叫做:讀已提交(read committed),或者也可以叫不可重複讀。這也就是事務的第二個隔離性。

在某些情況下,不可重複讀並不是問題,比如我們多次查詢某個資料當然以最後查詢得到的結果為主。但在另一些情況下就有可能發生問題,例如對於同乙個資料a和b依次查詢就可能不同,a和b就可能打起來了……

1、把隔離性調為read-committed(讀取提交內容)設定a的事務隔離級別,並進入事務做一次查詢:

2、b開始事務,並對記錄進行修改:

3、a再對user表進行查詢,發現記錄沒有受到影響:

4、b提交事務:

5、a再對user表查詢,發現記錄被修改:

試驗進行到這裡,你會發現,在同乙個事務中如果兩次讀取相同的資料時,最後的結果卻不一致。

這裡我們把這種現象稱為:不可重複讀。因為在第乙個事務讀取了資料之後,此時另乙個事務把該資料給修改了,這時候事務提交,那麼另乙個事務在第二次讀取的時候,結果就不一樣,乙個修改前的,乙個是修改後的。

但是細心的你會發現,既然你說此種隔離性是在事務提交後才釋放鎖,那麼在試驗過程中,在該資料未提交前,另乙個事務為什麼也是仍然可以讀取的呀。

是上面測試錯了嗎?不是的;

在這裡mysql使用了乙個併發版本控制機制,他們把它叫做mvcc,通俗的也就是說:mysql為了提高系統的併發量,在事務未提交前,雖然事務內操作的資料是鎖定狀態,但是另乙個事務仍然可以讀取資料的快照版本;像 oracle等大多數資料庫預設的就是讀提交這個級別的隔離性的。

而且不只是像上面在更新資料時出現這個問題,在插入資料時仍然會造成類似的這樣一種現象: mysql雖然鎖住了正在操作的資料行,但它仍然不會阻止另乙個事務往表插入新行新的資料。

比如:乙個事務讀取或更新了表裡的所有行,接者又有另乙個事務往該表裡插入乙個新行,在事務提交後;

原來讀取或更改過資料的事務又第二次讀取了相同的資料,這時候這個事務中兩次讀取的結果集行數就不一樣。原來更新了所有行,而現在讀出來發現竟然還有一行沒有更新。這就是所謂的幻讀

mysql依然採取的是mvcc併發版本控制來解決這個問題,還是讀取的快照資料。

具體是:如果事務中存在多次讀取同樣的資料,mysql第一次讀的時候仍然會保持選擇讀最新提交事務的資料,當第一次之後,之後再讀時,mysql會取第一次讀取的資料作為結果。

這樣就保證了同乙個事務多次讀取資料時資料的一致性。這時候,mysql把這種解決方案叫做:可重複讀(repeatable-read),也就是上述所寫的第三個隔離性,也是mysql預設的隔離級別。

注意:在可重複讀的隔離級別下,除了會保證讀操作的一致性外,在更新操作(當前讀)時也會保證資料的一致性,避免出現不可重複讀和幻讀的錯誤;

具體是:在mysql的可重複讀的隔離級別下,乙個事務中更新資料,並且事務不提交,另啟乙個事務insert插入新資料,這時候是無法插入新資料的,插入操作被阻塞;為什麼被阻塞呢?

因為在第乙個事務中進行更新資料時(當前讀),會使用行鎖 + 間隙鎖將表鎖住了,所以在第二個事務中插入操作被阻塞;只有當第乙個事務提交後,第二個事務中的插入操作才能被執行;

如果不阻塞的話,會存在什麼問題? 會存在幻讀的問題;例如:本來將全表資料的某個字段全部進行了更新,但是由於後面新增了資料,這些新增資料的那個欄位並沒有被更新,再次檢視時就跟出現了幻覺一樣;所以為了解決幻讀的問題,在可重複讀隔離級別中提供了間隙鎖,使用行鎖+間隙鎖將表鎖住,讓所有操作都不能修改資料 。

注意:innodb儲存引擎中有對鎖等待超時時間的配置,在規定時間內沒有獲取到鎖的話,則此事務被中斷,需要應用**進行手動回滾或重試;

注意:幻讀和不可重複讀的區別:

該隔離級別會自動在鎖住你要操作的整個表的資料,如果另乙個程序事務想要操作表裡的任何資料就需要等待獲得鎖的程序操作完成釋放鎖。

可避免髒讀、不可重複讀、幻讀的發生。當然效能會下降很多,會導致很多的程序相互排隊競爭鎖。

上面所說的四種隔離性的鎖機制應用是資料庫自動完成的,不需要人為干預。

隔離級別的設定只對當前會話連線有效。對於使用mysql命令視窗而言,乙個視窗就相當於乙個鏈結,當前視窗設定的隔離級別只對當前視窗中的事務有效 。

一文帶你了解可重入鎖

可重入鎖就是乙個執行緒給某個資源上了鎖之後,在不釋放鎖的情況下,繼續對該資源進行上鎖。那麼可重入鎖有什麼好處呢?可重入鎖降低了程式設計的複雜性 減少了死鎖的發生 舉個栗子 public class myreentrant if index 10 start 可重入鎖有兩種實現,分別是synchron...

資料庫鎖 隔離級別

併發控制主要是為了多執行緒操作時帶來的資源讀寫問題。如果不加以空間可能會出現死鎖,讀髒資料 不可重複讀 丟失更新等異常。併發操作可以通過加鎖的方式進行控制,鎖又可分為樂觀鎖和悲觀鎖。悲觀鎖 pessimistic locking 併發模式假定系統中存在足夠多的資料修改操作,以致於任何確定的讀操作都可...

一文帶你了解數倉智慧型運維框架

摘要 本文將針對gaussdb dws 內排程器的底層運作原理進行簡單說明,並針對排程模式擴容重分布進行介紹。隨著gaussdb dws 的快速發展,gaussdb dws 目前整合了眾多運維操作,其中大部分運維操作均需占用使用者資源,如io mem cpu 網路 磁碟空間等,且無法依據使用者業務負...