日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

mysql 乐观锁 脏读_mysql 丢失更新1和2、脏读、不可重复读和幻读 事务隔离级别 悲观锁 乐观锁...

發(fā)布時(shí)間:2025/3/21 数据库 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 乐观锁 脏读_mysql 丢失更新1和2、脏读、不可重复读和幻读 事务隔离级别 悲观锁 乐观锁... 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

事務(wù)是現(xiàn)代關(guān)系型數(shù)據(jù)庫(kù)的核心之一。在多個(gè)事務(wù)并發(fā)操作數(shù)據(jù)庫(kù)(多線程、網(wǎng)絡(luò)并發(fā)等)的時(shí)候,如果沒(méi)有有效的避免機(jī)制,就會(huì)出現(xiàn)以下幾種問(wèn)題:

(

第一類丟失更新

A事務(wù)撤銷(xiāo)時(shí),把已經(jīng)提交的B事務(wù)的更新數(shù)據(jù)覆蓋了。這種錯(cuò)誤可能造成很?chē)?yán)重的問(wèn)題,通過(guò)下面的賬戶取款轉(zhuǎn)賬就可以看出來(lái):

時(shí)間

取款事務(wù)A

轉(zhuǎn)賬事務(wù)B

T1

開(kāi)始事務(wù)

T2

開(kāi)始事務(wù)

T3

查詢賬戶余額為1000元

T4

查詢賬戶余額為1000元

T5

匯入100元把余額改為1100元

T6

提交事務(wù)

T7

取出100元把余額改為900元

T8

撤銷(xiāo)事務(wù)

T9

余額恢復(fù)為1000?元(丟失更新)

A事務(wù)在撤銷(xiāo)時(shí),“不小心”將B事務(wù)已經(jīng)轉(zhuǎn)入賬戶的金額給抹去了。

SQL92沒(méi)有定義這種現(xiàn)象,標(biāo)準(zhǔn)定義的所有隔離界別都不允許第一類丟失更新發(fā)生。

第二類丟失更新

A事務(wù)覆蓋B事務(wù)已經(jīng)提交的數(shù)據(jù),造成B事務(wù)所做操作丟失:

時(shí)間

轉(zhuǎn)賬事務(wù)A

取款事務(wù)B

T1

開(kāi)始事務(wù)

T2

開(kāi)始事務(wù)

T3

查詢賬戶余額為1000元

T4

查詢賬戶余額為1000元

T5

取出100元把余額改為900元

T6

提交事務(wù)

T7

匯入100元

T8

提交事務(wù)

T9

把余額改為1100?元(丟失更新)

上面的例子里由于支票轉(zhuǎn)賬事務(wù)覆蓋了取款事務(wù)對(duì)存款余額所做的更新,導(dǎo)致銀行最后損失了100元,相反如果轉(zhuǎn)賬事務(wù)先提交,那么用戶賬戶將損失100元。

)

第一類丟失更新(Lost Update)

在完全未隔離事務(wù)的情況下,兩個(gè)事務(wù)更新同一條數(shù)據(jù)資源,某一事務(wù)完成,另一事務(wù)異常終止,回滾造成第一個(gè)完成的更新也同時(shí)丟失 。這個(gè)問(wèn)題現(xiàn)代關(guān)系型數(shù)據(jù)庫(kù)已經(jīng)不會(huì)發(fā)生,就不在這里占用篇幅,有興趣的可以自行百度。

臟讀(Dirty Read)

A事務(wù)執(zhí)行過(guò)程中,B事務(wù)讀取了A事務(wù)的修改。但是由于某些原因,A事務(wù)可能沒(méi)有完成提交,發(fā)生RollBack了操作,則B事務(wù)所讀取的數(shù)據(jù)就會(huì)是不正確的。這個(gè)未提交數(shù)據(jù)就是臟讀(Dirty Read)。臟讀產(chǎn)生的流程如下:

不可重復(fù)讀(Nonrepeatable Read)

B事務(wù)讀取了兩次數(shù)據(jù),在這兩次的讀取過(guò)程中A事務(wù)修改了數(shù)據(jù),B事務(wù)的這兩次讀取出來(lái)的數(shù)據(jù)不一樣。B事務(wù)這種讀取的結(jié)果,即為不可重復(fù)讀(Nonrepeatable Read)。不可重復(fù)讀的產(chǎn)生的流程如下:

不可重復(fù)讀有一種特殊情況,兩個(gè)事務(wù)更新同一條數(shù)據(jù)資源,后完成的事務(wù)會(huì)造成先完成的事務(wù)更新丟失。這種情況就是大名鼎鼎的第二類丟失更新。主流的數(shù)據(jù)庫(kù)已經(jīng)默認(rèn)屏蔽了第一類丟失更新問(wèn)題(即:后做的事務(wù)撤銷(xiāo),發(fā)生回滾造成已完成事務(wù)的更新丟失),但我們編程的時(shí)候仍需要特別注意第二類丟失更新。它產(chǎn)生的流程如下:

幻讀(Phantom Read)

B事務(wù)讀取了兩次數(shù)據(jù),在這兩次的讀取過(guò)程中A事務(wù)添加了數(shù)據(jù),B事務(wù)的這兩次讀取出來(lái)的集合不一樣。幻讀產(chǎn)生的流程如下:

這個(gè)流程看起來(lái)和不可重復(fù)讀差不多,但幻讀強(qiáng)調(diào)的集合的增減,而不是單獨(dú)一條數(shù)據(jù)的修改。

數(shù)據(jù)庫(kù)隔離級(jí)別

為了解決上面提及的并發(fā)問(wèn)題,主流關(guān)系型數(shù)據(jù)庫(kù)都會(huì)提供四種事務(wù)隔離級(jí)別。

讀未提交(Read Uncommitted)

在該隔離級(jí)別,所有事務(wù)都可以看到其他未提交事務(wù)的執(zhí)行結(jié)果。本隔離級(jí)別是最低的隔離級(jí)別,雖然擁有超高的并發(fā)處理能力及很低的系統(tǒng)開(kāi)銷(xiāo),但很少用于實(shí)際應(yīng)用。因?yàn)椴捎眠@種隔離級(jí)別只能防止第一類更新丟失問(wèn)題,不能解決臟讀,不可重復(fù)讀及幻讀問(wèn)題。

讀已提交(Read Committed)

這是大多數(shù)數(shù)據(jù)庫(kù)系統(tǒng)的默認(rèn)隔離級(jí)別(但不是MySQL默認(rèn)的)。它滿足了隔離的簡(jiǎn)單定義:一個(gè)事務(wù)只能看見(jiàn)已經(jīng)提交事務(wù)所做的改變。這種隔離級(jí)別可以防止臟讀問(wèn)題,但會(huì)出現(xiàn)不可重復(fù)讀及幻讀問(wèn)題。

可重復(fù)讀(Repeatable Read)

這是MySQL的默認(rèn)事務(wù)隔離級(jí)別,它確保同一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí),會(huì)看到同樣的數(shù)據(jù)行。這種隔離級(jí)別可以防止除幻讀外的其他問(wèn)題。

可串行化(Serializable)

這是最高的隔離級(jí)別,它通過(guò)強(qiáng)制事務(wù)排序,使之不可能相互沖突,從而解決幻讀、第二類更新丟失問(wèn)題。在這個(gè)級(jí)別,可以解決上面提到的所有并發(fā)問(wèn)題,但可能導(dǎo)致大量的超時(shí)現(xiàn)象和鎖競(jìng)爭(zhēng),通常數(shù)據(jù)庫(kù)不會(huì)用這個(gè)隔離級(jí)別,我們需要其他的機(jī)制來(lái)解決這些問(wèn)題:樂(lè)觀鎖和悲觀鎖。

這四種隔離級(jí)別會(huì)產(chǎn)生的問(wèn)題如下(網(wǎng)上到處都有,懶得畫(huà)了):

如何使用數(shù)據(jù)庫(kù)的隔離級(jí)別

很多文章博客在介紹完這些隔離級(jí)別以后,就沒(méi)有以后了。讀的人一般會(huì)覺(jué)得,嗯,是這么回事,我知道了!

學(xué)習(xí)一個(gè)知識(shí)點(diǎn),是需要實(shí)踐的。比如下面這個(gè)常見(jiàn)而又異常嚴(yán)重的情況:

圖中是典型的第二類丟失更新問(wèn)題,后果異常嚴(yán)重。我們這里就以讀已提交(Read Committed)及以下隔離級(jí)別中會(huì)出現(xiàn)不可重復(fù)讀現(xiàn)象為例。從上面的表格可以看出,當(dāng)事務(wù)隔離級(jí)別為可重復(fù)讀(Repeatable Read)時(shí)可以避免。(事務(wù)隔離級(jí)別)

悲觀鎖:

顧名思義,很悲觀,就是每次拿數(shù)據(jù)的時(shí)候都認(rèn)為別的線程會(huì)修改數(shù)據(jù),所以在每次拿的時(shí)候都會(huì)給數(shù)據(jù)上鎖。上鎖之后,當(dāng)別的線程想要拿數(shù)據(jù)時(shí),就會(huì)阻塞,直到給數(shù)據(jù)上鎖的線程將事務(wù)提交或者回滾。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)里就用到了很多這種鎖機(jī)制,比如行鎖,表鎖,共享鎖,排他鎖等,都是在做操作之前先上鎖。

行鎖:

下面演示行鎖,打開(kāi)兩個(gè)mysql命令行界面,兩個(gè)線程分別執(zhí)行如下操作:(左邊先執(zhí)行)

左邊的線程,在事務(wù)中通過(guò)select for update語(yǔ)句給sid = 1的數(shù)據(jù)行上了鎖。右邊的線程此時(shí)可以使用select語(yǔ)句讀取數(shù)據(jù),但是如果也使用select for update語(yǔ)句,就會(huì)阻塞,使用update,add,delete也會(huì)阻塞。

當(dāng)左邊的線程將事務(wù)提交(或者回滾),右邊的線程就會(huì)獲取鎖,線程不再阻塞:

此時(shí),右邊的線程獲取鎖,左邊的線程如果執(zhí)行類似操作,也會(huì)被阻塞:

表鎖:

上述例子中,如果使用如下語(yǔ)句就是使用的表鎖:

select * from student for update;

頁(yè)鎖:

行鎖鎖指定行,表鎖鎖整張表,頁(yè)鎖是折中實(shí)現(xiàn),即一次鎖定相鄰的一組記錄。

共享鎖:

共享鎖又稱為讀鎖,一個(gè)線程給數(shù)據(jù)加上共享鎖后,其他線程只能讀數(shù)據(jù),不能修改。

排他鎖:

排他鎖又稱為寫(xiě)鎖,和共享鎖的區(qū)別在于,其他線程既不能讀也不能修改。

樂(lè)觀鎖:

樂(lè)觀鎖其實(shí)不會(huì)上鎖。顧名思義,很樂(lè)觀,它默認(rèn)別的線程不會(huì)修改數(shù)據(jù),所以不會(huì)上鎖。只是在更新前去判斷別的線程在此期間有沒(méi)有修改數(shù)據(jù),如果修改了,會(huì)交給業(yè)務(wù)層去處理。

常用的實(shí)現(xiàn)方式是使用版本戳,例如在一張表中添加一個(gè)整型字段version,每更新version++,比如某個(gè)時(shí)刻version=1,線程A讀取了此version=1,線程B也讀取了此version=1,當(dāng)線程A更新數(shù)據(jù)之前,判斷version仍然為1,更新成功,version++變?yōu)?,但是當(dāng)線程B再提交更新時(shí),發(fā)現(xiàn)version變?yōu)?了,與之前讀的version=1不一致,就知道有別的線程更新了數(shù)據(jù),這個(gè)時(shí)候就會(huì)進(jìn)行業(yè)務(wù)邏輯的處理。

通常情況下,寫(xiě)操作較少時(shí),使用樂(lè)觀鎖,寫(xiě)操作較多時(shí),使用悲觀鎖。

丟失更新: 當(dāng)兩個(gè)事物或多個(gè)事務(wù)都更新了同一條數(shù)據(jù),但是這些事務(wù)彼此之間都不知道其他事務(wù)進(jìn)行的修改,因此第二個(gè)更改覆蓋了第一次的更改,說(shuō)白了,就是事務(wù)A還沒(méi)有提交之后,但是這個(gè)時(shí)候事務(wù)B更新了數(shù)據(jù),那么事務(wù)A就丟失更新了。

解決方案: 樂(lè)觀鎖+悲觀鎖

悲觀鎖: 數(shù)據(jù)庫(kù)的一種鎖機(jī)制,悲觀鎖分成兩種,分別是共享鎖和排它鎖

添加共享鎖方式:select * from account lock in share mode ;

添加排它鎖方式:select * from account for update;

下面說(shuō)一下共享鎖: 共享鎖就是,例如 我在客戶端A 給數(shù)據(jù)C 添加了共享鎖,此時(shí)我在客戶端B只能添加共享鎖進(jìn)行查看,沒(méi)有修改的權(quán)利,如果我想要在客戶端B進(jìn)行修改,我只能在A處commit才能進(jìn)行修改。

下面說(shuō)一下排它鎖:排它鎖就是我在客戶端A 給數(shù)據(jù)C添加了排它鎖,那么我在客戶端B只能在客戶端 A commit之后,才能select數(shù)據(jù),換句話說(shuō),只要我在客戶端B用鎖進(jìn)行了查詢,那我我都需要等待Acommit之后,如果此時(shí)我客戶端B不加鎖,我是可以查詢到的。這個(gè)排它鎖很像數(shù)據(jù)庫(kù)隔離級(jí)別中的最高的隔離級(jí)別。但是排它鎖是鎖住了一條數(shù)據(jù),而排它鎖是鎖上了這條數(shù)據(jù)。

說(shuō)完了悲觀鎖,那么我們?cè)谡f(shuō)說(shuō)樂(lè)觀鎖。

樂(lè)觀鎖:就是假設(shè)丟失更新不存在,它使用的是數(shù)據(jù)庫(kù)的字段進(jìn)行加測(cè)。 例如我在我的字段中添加一個(gè)字段,字段的類型是 timestamp 在插入和修改時(shí) 都會(huì)自動(dòng)更新為當(dāng)前時(shí)間 ,我根據(jù)我的sql條件進(jìn)行判斷,如果我的時(shí)間不符合,那么我的更新失敗。

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的mysql 乐观锁 脏读_mysql 丢失更新1和2、脏读、不可重复读和幻读 事务隔离级别 悲观锁 乐观锁...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。