淺談一下mysql數(shù)據(jù)庫底層原理
1.數(shù)據(jù)庫事務(wù)的基本特性。
原子性:
事務(wù)中的所有操作要么全部提交成功,要么全部失敗回滾。
場景:UPDATE cs_user SET age = 18 , gender = '女' WHERE id = 4。要么全部更新要么更新失敗,不會出現(xiàn)age更新成功,gender更新失敗。
一致性:
據(jù)庫總是從給一個一致性的狀態(tài)轉(zhuǎn)換到另一個一致性的狀態(tài)。
場景:比如規(guī)定某個表的字段age大于等于12小于18時,字段type為青少年,而數(shù)據(jù)庫中存在age=16的時候,type='兒童'。
隔離性:
一個事務(wù)所做的修改在提交之前對其它事務(wù)是不可見的。兩個以上的事務(wù)不會出現(xiàn)交錯執(zhí)行的狀態(tài).因為這樣可能會導(dǎo)致數(shù)據(jù)不一致。
持久性:
一旦事務(wù)提交,其所做的修改便會永久保存在數(shù)據(jù)庫中。
事務(wù)在并發(fā)環(huán)境下出現(xiàn)的問題。
臟讀(Dirty Read):一個事務(wù)讀取了另一個事務(wù)未提交的數(shù)據(jù)。如果另一個事務(wù)回滾,則讀取的數(shù)據(jù)將是無效的。
不可重復(fù)讀(Non-repeatable Read):同一事務(wù)內(nèi),兩次讀取同一數(shù)據(jù)得到的結(jié)果不同。這是因為在兩次讀取之間,另一個事務(wù)修改了該數(shù)據(jù)。
幻讀(Phantom Read):同一事務(wù)內(nèi),兩次查詢得到的結(jié)果集不同。這是因為在兩次查詢之間,另一個事務(wù)插入或刪除了一些數(shù)據(jù)。
丟失修改(Lost Update):兩個或多個事務(wù)同時修改同一數(shù)據(jù),其中一個事務(wù)的修改被另一個事務(wù)覆蓋,導(dǎo)致修改丟失。
不可重復(fù)讀的和幻讀很容易混淆,不可重復(fù)讀側(cè)重于修改,幻讀側(cè)重于新增或刪除。解決不可重復(fù)讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表。
對于這些問題的解決方法一般是有:事務(wù)隔離級別,樂觀鎖和悲觀鎖,MVCC(多版本并發(fā)控制)。
事務(wù)隔離級別
數(shù)據(jù)庫提供了多種事務(wù)隔離級別,不同的隔離級別提供了不同的并發(fā)控制機(jī)制,以解決并發(fā)問題。
以下是數(shù)據(jù)庫的每一個事務(wù)隔離級別的詳細(xì)介紹:
READ UNCOMMITTED(讀未提交):該隔離級別允許事務(wù)讀取其他事務(wù)未提交的數(shù)據(jù),可能會出現(xiàn)臟讀、不可重復(fù)讀和幻讀的問題。
READ COMMITTED(讀已提交):該隔離級別只允許事務(wù)讀取其他事務(wù)已提交的數(shù)據(jù),可以避免臟讀問題,但不可避免不可重復(fù)讀和幻讀的問題。
REPEATABLE READ(可重復(fù)讀):該隔離級別保證在同一事務(wù)中多次讀取同一數(shù)據(jù)得到的結(jié)果是一致的,可以避免臟讀和不可重復(fù)讀的問題,但無法避免幻讀。
SERIALIZABLE(串行化):該隔離級別保證事務(wù)串行執(zhí)行,避免了以上所有并發(fā)問題,但會影響并發(fā)性能。
READ UNCOMMITTED(讀未提交)
在READ UNCOMMITTED級別下,事務(wù)可以讀取未提交的數(shù)據(jù),沒有對數(shù)據(jù)進(jìn)行加鎖或版本控制。當(dāng)一個事務(wù)讀取數(shù)據(jù)時,即使另一個事務(wù)正在修改該數(shù)據(jù),也不會阻塞讀取操作。這種實現(xiàn)方式可以提高讀取性能,但會導(dǎo)致臟讀的問題。
優(yōu)點:
讀取性能高:由于不需要加鎖或版本控制,因此讀取性能較高。
無鎖操作:該隔離級別不需要對數(shù)據(jù)進(jìn)行加鎖操作,因此可以避免鎖的競爭問題。
缺點:
臟讀問題:在READ UNCOMMITTED級別下,事務(wù)可以讀取其他事務(wù)未提交的數(shù)據(jù),因此可能會讀取到無效數(shù)據(jù),導(dǎo)致臟讀的問題。
不可重復(fù)讀問題:由于其他事務(wù)可以修改數(shù)據(jù),因此同一事務(wù)內(nèi)兩次讀取同一數(shù)據(jù)得到的結(jié)果可能不同。
幻讀問題:由于其他事務(wù)可以插入或刪除數(shù)據(jù),因此同一事務(wù)內(nèi)兩次查詢得到的結(jié)果集可能不同??赡軐?dǎo)致數(shù)據(jù)不一致:由于讀取的數(shù)據(jù)可能是未提交的數(shù)據(jù),因此可能會導(dǎo)致數(shù)據(jù)不一致的問題。
對于這個隔離級別,幾乎無法解決任何對于數(shù)據(jù)庫并發(fā)環(huán)境下數(shù)據(jù)不一致的錯誤,但在一些對數(shù)據(jù)一致性要求不高,但讀取性能要求較高的系統(tǒng)中,可以考慮使用該隔離級別。
READ COMMITTED(讀已提交)
在READ COMMITTED級別下,事務(wù)只能讀取已提交的數(shù)據(jù),需要對數(shù)據(jù)進(jìn)行加鎖或版本控制。當(dāng)一個事務(wù)讀取數(shù)據(jù)時,如果另一個事務(wù)正在修改該數(shù)據(jù),則需要等待該事務(wù)提交后才能讀取。這種實現(xiàn)方式可以避免臟讀的問題,但可能會無法避免不可重復(fù)讀和幻讀的問題。
優(yōu)點:
避免臟讀問題:由于只允許讀取已提交的數(shù)據(jù),因此可以避免臟讀的問題。
數(shù)據(jù)一致性較高:由于只讀取已提交的數(shù)據(jù),因此數(shù)據(jù)一致性較高。
缺點:
不可重復(fù)讀問題:由于其他事務(wù)可以修改數(shù)據(jù),因此同一事務(wù)內(nèi)兩次讀取同一數(shù)據(jù)得到的結(jié)果可能不同。
幻讀問題:由于其他事務(wù)可以插入或刪除數(shù)據(jù),因此同一事務(wù)內(nèi)兩次查詢得到的結(jié)果集可能不同。
鎖的競爭問題:由于需要對數(shù)據(jù)進(jìn)行加鎖,因此可能會導(dǎo)致鎖的競爭問題。
這個隔離級別解決了一部分并發(fā)問題,但是還有一部分問題沒有解決,適合應(yīng)用于對數(shù)據(jù)一致性要求較高的系統(tǒng)。如果需要更高的隔離級別,可以考慮使用REPEATABLE READ或SERIALIZABLE級別。
REPEATABLE READ(可重復(fù)讀)
在InnoDB中是這樣的:RR隔離級別保證對讀取到的記錄加鎖 (記錄鎖),同時保證對讀取的范圍加鎖,新的滿足查詢條件的記錄不能夠插入 (間隙鎖),因此不存在幻讀現(xiàn)象。但是標(biāo)準(zhǔn)的RR只能保證在同一事務(wù)中多次讀取同樣記錄的結(jié)果是一致的,而無法解決幻讀問題。InnoDB的幻讀解決是依靠MVCC的實現(xiàn)機(jī)制做到的。Mysql默認(rèn)的隔離級別是RR。
優(yōu)點:
避免臟讀和不可重復(fù)讀問題:由于需要對數(shù)據(jù)進(jìn)行版本控制,因此可以避免臟讀和不可重復(fù)讀的問題。
數(shù)據(jù)一致性較高:由于保證了同一事務(wù)內(nèi)多次讀取同一數(shù)據(jù)得到的結(jié)果一致,因此數(shù)據(jù)一致性較高。
缺點:
鎖的競爭問題:由于需要對數(shù)據(jù)進(jìn)行版本控制,因此可能會導(dǎo)致鎖的競爭問題。
版本控制開銷:由于需要對數(shù)據(jù)進(jìn)行版本控制,因此可能會增加數(shù)據(jù)庫的存儲和計算開銷。
幻讀解決
InnoDB的幻讀解決是依靠MVCC的實現(xiàn)機(jī)制: (增加系統(tǒng)版本號,每次事務(wù)操作,會比較系統(tǒng)版本號) InnoDB為每行記錄添加了一個版本號(系統(tǒng)版本號),每當(dāng)修改數(shù)據(jù)時,版本號加一。在讀取事務(wù)開始時,系統(tǒng)會給事務(wù)一個當(dāng)前版本號,事務(wù)會讀取版本號<=當(dāng)前版本號的數(shù)據(jù),這時就算另一個事務(wù)插入一個數(shù)據(jù),并立馬提交,新插入這條數(shù)據(jù)的版本號會比讀取事務(wù)的版本號高,因此讀取事務(wù)讀的數(shù)據(jù)還是不會變。例如:此時books表中有5條數(shù)據(jù),版本號為1 事務(wù)A,系統(tǒng)版本號2:select * from books;因為1<=2所以此時會讀取5條數(shù)據(jù)。 事務(wù)B,系統(tǒng)版本號3:insert into books ...,插入一條數(shù)據(jù),新插入的數(shù)據(jù)版本號為3,而其他的數(shù)據(jù)的版本號仍然是2,插入完成之后commit,事務(wù)結(jié)束。 事務(wù)A,系統(tǒng)版本號2:再次select * from books;只能讀取<=2的數(shù)據(jù),事務(wù)B新插入的那條數(shù)據(jù)版本號為3,因此讀不出來,解決了幻讀的問題,而且兩個事務(wù)同時修改同一數(shù)據(jù),則會生成兩個不同的版本,從而避免數(shù)據(jù)丟失的問題,解決了丟失修改問題。
mysql鎖
在mysql中使用的鎖一般是兩種類型,樂觀鎖和悲觀鎖。
樂觀鎖概念
是由我們自己實現(xiàn)的一個版本控制。在表中的數(shù)據(jù)進(jìn)行操作時(更新),先給數(shù)據(jù)表加一個版本(version)字段,每操作一次,將那條記錄的版本號加1。也就是先查詢出那條記錄,獲取出version字段,如果要對那條記錄進(jìn)行操作(更新),則先判斷此刻version的值是否與剛剛查詢出來時的version的值相等,如果相等,則說明這段期間,沒有其他程序?qū)ζ溥M(jìn)行操作,則可以執(zhí)行更新,將version字段的值加1;如果更新時發(fā)現(xiàn)此刻的version值與剛剛獲取出來的version的值不相等,則說明這段期間已經(jīng)有其他程序?qū)ζ溥M(jìn)行操作了,則不進(jìn)行更新操作
悲觀鎖概念
這個由數(shù)據(jù)庫實現(xiàn),對于悲觀鎖在操作數(shù)據(jù)時,認(rèn)為此操作會出現(xiàn)數(shù)據(jù)沖突,所以在進(jìn)行每次操作時都要通過獲取鎖才能進(jìn)行對相同數(shù)據(jù)的操作。在悲觀鎖中又有兩種類型,分別是共享鎖與排它鎖。
共享鎖(讀鎖)
對于共享鎖來說,他的作用是在一個事務(wù)對數(shù)據(jù)A加上共享鎖后,其他的事務(wù)只能在對數(shù)據(jù)A加共享鎖,無法加其他鎖,只有全部共享鎖釋放后才能加其他鎖(基本上就是排它鎖)。這句話的意思其實就是,有一個事務(wù)正在讀數(shù)據(jù)A,那么其他事務(wù)也只能讀數(shù)據(jù)A,而無法修改數(shù)據(jù)A,只有在所有事務(wù)對數(shù)據(jù)A的訪問都完成后,才能進(jìn)行修改。
排它鎖(寫鎖)
對于排它鎖來說,作用是在一個事務(wù)對數(shù)據(jù)A加上排它鎖后,只有這個事務(wù)可以對數(shù)據(jù)進(jìn)行讀取和修改,其他的事務(wù)都無法對這個數(shù)據(jù)進(jìn)行讀取和修改,當(dāng)然也無法對這個數(shù)據(jù)加鎖。
使用方式:在需要執(zhí)行的語句后面加上for update
就可以了
行鎖和表鎖
對于悲觀鎖來說
有行鎖和表鎖兩種區(qū)別,
行鎖是給某一行加上鎖,也就是一條記錄加上鎖。
行級鎖都是基于索引的,如果一條SQL語句用不到索引是不會使用行級鎖的,會使用表級鎖(這也是為什么sql語句盡量保證走索引原因之一)
表鎖:沒有使用索引的情況是鎖定全表的。
死鎖
死鎖(Deadlock) 所謂死鎖:是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去。此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的進(jìn)程稱為死鎖進(jìn)程。由于資源占用是互斥的,當(dāng)某個進(jìn)程提出申請資源后,使得有關(guān)進(jìn)程在無外力協(xié)助下,永遠(yuǎn)分配不到必需的資源而無法繼續(xù)運行,這就產(chǎn)生了一種特殊現(xiàn)象死鎖。
到此這篇關(guān)于淺談一下mysql數(shù)據(jù)庫底層原理的文章就介紹到這了,更多相關(guān)mysql數(shù)據(jù)庫底層原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
centos7環(huán)境下源碼安裝mysql5.7.16的方法詳解
這篇文章主要介紹了centos7環(huán)境下源碼安裝mysql5.7.16的方法,詳細(xì)分析了centos7環(huán)境下MySQL安裝的相關(guān)步驟、操作命令、配置方法與注意事項,需要的朋友可以參考下2020-02-02mysql查詢時offset過大影響性能的原因和優(yōu)化詳解
這篇文章主要給大家介紹了關(guān)于mysql查詢時offset過大影響性能的原因和優(yōu)化的相關(guān)資料,并在文末跟大家分享了MYSQL中l(wèi)imit,offset的區(qū)別,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-06-06mysql之key和index的區(qū)別及創(chuàng)建刪除索引方式
這篇文章主要介紹了mysql之key和index的區(qū)別及創(chuàng)建刪除索引方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12MySQL計算兩個日期相差的天數(shù)、月數(shù)、年數(shù)
這篇文章主要介紹了MySQL計算兩個日期相差的天數(shù)、月數(shù)、年數(shù),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-08-08MySQL8.0設(shè)置遠(yuǎn)程訪問權(quán)限的方法
這篇文章主要介紹了MySQL8.0設(shè)置遠(yuǎn)程訪問權(quán)限的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11詳解使用navicat連接遠(yuǎn)程linux mysql數(shù)據(jù)庫出現(xiàn)10061未知故障
這篇文章主要介紹了navicat連接遠(yuǎn)程linux mysql數(shù)據(jù)庫出現(xiàn)10061未知故障,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04The MySQL server is running with the --read-only option so i
1209 - The MySQL server is running with the --read-only option so it cannot execute this statement2020-08-08