日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

【mysql】关于事务的隔离级别

發(fā)布時間:2025/7/14 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【mysql】关于事务的隔离级别 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、鎖的種類

MySQL中鎖的種類很多,有常見的表鎖和行鎖,也有新加入的Metadata Lock等等,表鎖是對一整張表加鎖,雖然可分為讀鎖和寫鎖,但畢竟是鎖住整張表,會導(dǎo)致并發(fā)能力下降,一般是做ddl處理時使用。

行鎖則是鎖住數(shù)據(jù)行,這種加鎖方法比較復(fù)雜,但是由于只鎖住有限的數(shù)據(jù),對于其它數(shù)據(jù)不加限制,所以并發(fā)能力強(qiáng),MySQL一般都是用行鎖來處理并發(fā)事務(wù)

二、鎖粒度

為了盡可能提高數(shù)據(jù)庫的并發(fā)度,每次鎖定的數(shù)據(jù)范圍越小越好,理論上每次只鎖定當(dāng)前操作的數(shù)據(jù)的方案會得到最大的并發(fā)度,但是管理鎖是很耗資源的事情(涉及獲取,檢查,釋放鎖等動作),因此數(shù)據(jù)庫系統(tǒng)需要在高并發(fā)響應(yīng)和系統(tǒng)性能兩方面進(jìn)行平衡,這樣就產(chǎn)生了“鎖粒度(Lock granularity)”的概念

一種提高共享資源并發(fā)發(fā)性的方式是讓鎖定對象更有選擇性。盡量只鎖定需要修改的部分?jǐn)?shù)據(jù),而不是所有的資源。更理想的方式是,只對會修改的數(shù)據(jù)片進(jìn)行精確的鎖定。任何時候,在給定的資源上,鎖定的數(shù)據(jù)量越少,則系統(tǒng)的并發(fā)程度越高,只要相互之間不發(fā)生沖突即可

但是,加鎖也需要消耗資源。鎖的各種操作,包括獲得鎖、檢查鎖和是否已經(jīng)解除、釋放鎖等,都會增加系統(tǒng)的開銷。所謂鎖策略,就是在鎖的開銷和數(shù)據(jù)的安全性之間尋求平衡

表鎖:管理鎖的開銷最小,同時允許的并發(fā)量也最小的鎖機(jī)制。MyIsam存儲引擎使用的鎖機(jī)制。當(dāng)要寫入數(shù)據(jù)時,把整個表都鎖上,此時其他讀、寫動作一律等待。除了MyIsam存儲引擎使用這種鎖策略外,MySql本身也使用表鎖來執(zhí)行某些特定動作,比如alter table。另外,寫鎖比讀鎖有更高的優(yōu)先級,因此一個寫鎖可能會被插入到讀鎖隊列的前面。

行鎖:可以支持最大并發(fā)的鎖策略(同時也帶來了最大的鎖開銷)。InnoDB和Falcon兩種存儲引擎都采用這種策略。行級鎖只在存儲引擎層實現(xiàn),而MySQL服務(wù)器層沒有實現(xiàn)。服務(wù)器層完全不了解存儲引擎中的鎖實現(xiàn)。MySql是一種開放的架構(gòu),你可以實現(xiàn)自己的存儲引擎,并實現(xiàn)自己的鎖粒度策略,不像Oracle,你沒有機(jī)會改變鎖策略,Oracle采用的是行鎖。

三、死鎖

死鎖是指兩個或者多個事務(wù)在同一資源上相互占用,并請求鎖定對方占用的資源,從而導(dǎo)致惡性循環(huán)的假象。多個事務(wù)同時鎖定同一個資源時,也會產(chǎn)生死鎖。數(shù)據(jù)庫系統(tǒng)實現(xiàn)了各種死鎖檢測和死鎖超時的機(jī)制,InnoDB目前處理死鎖的方法是,將持有最少行級排他鎖的事務(wù)進(jìn)行回滾

四、事務(wù)ACID原則

從業(yè)務(wù)角度出發(fā),對數(shù)據(jù)庫的一組操作要求保持4個特征:

  • Atomicity(原子性):一個事務(wù)必須被視為一個不可分割的最小工作單元,整個事務(wù)中的所有操作要么全部提交成功,要么全部失敗回滾,對于一個事務(wù)來說,不可能只執(zhí)行其中的一部分操作,這就是事務(wù)的原子性
  • Consistency(一致性):數(shù)據(jù)庫總是從一個一致性狀態(tài)轉(zhuǎn)換到另一個一致狀態(tài)。下面的銀行列子會說到
  • Isolation(隔離性):通常來說,一個事務(wù)所做的修改在最終提交以前,對其他事務(wù)是不可見的
  • Durability(持久性):一旦事務(wù)提交,則其所做的修改就會永久保存到數(shù)據(jù)庫中。此時即使系統(tǒng)崩潰,修改的數(shù)據(jù)也不會丟失。(持久性的安全性與刷新日志級別也存在一定關(guān)系,不同的級別對應(yīng)不同的數(shù)據(jù)安全級別。)

為了更好地理解ACID,以銀行賬戶轉(zhuǎn)賬為例:

BEGIN; SELECT balance FROM checking WHERE customer_id = 10233276; UPDATE checking SET balance = balance - 200.00 WHERE customer_id = 10233276; UPDATE savings SET balance = balance + 200.00 WHERE customer_id = 10233276; COMMIT;

原子性:要么完全提交(10233276的checking余額減少200,savings?的余額增加200),要么完全回滾(兩個表的余額都不發(fā)生變化)

一致性:這個例子的一致性體現(xiàn)在 200元不會因為數(shù)據(jù)庫系統(tǒng)運行到第3行之后,第4行之前時崩潰而不翼而飛,因為事物還沒有提交

隔離性:允許在一個事務(wù)中的操作語句會與其他事務(wù)的語句隔離開,比如事務(wù)A運行到第3行之后,第4行之前,此時事務(wù)B去查詢checking余額時,它仍然能夠看到在事務(wù)A中被減去的200元(賬戶錢不變),因為事務(wù)A和B是彼此隔離的。在事務(wù)A提交之前,事務(wù)B觀察不到數(shù)據(jù)的改變

五、并發(fā)問題可歸納為以下幾類

1、丟失更新

撤銷一個事務(wù)時,把其他事務(wù)已提交的更新數(shù)據(jù)覆蓋

例子:A和B事務(wù)并發(fā)執(zhí)行,A事務(wù)執(zhí)行更新后,提交;B事務(wù)在A事務(wù)更新后,B事務(wù)結(jié)束前也做了對該行數(shù)據(jù)的更新操作,然后回滾,則兩次更新操作都丟失了

2、臟讀

一個事務(wù)讀到另一個事務(wù)未提交的更新數(shù)據(jù)

例子:A和B事務(wù)并發(fā)執(zhí)行,B事務(wù)執(zhí)行更新后,A事務(wù)查詢B事務(wù)沒有提交的數(shù)據(jù),B事務(wù)回滾,則A事務(wù)得到的數(shù)據(jù)不是數(shù)據(jù)庫中的真實數(shù)據(jù)。也就是臟數(shù)據(jù),即和數(shù)據(jù)庫中不一致的數(shù)據(jù)

3、不可重復(fù)讀

一個事務(wù)讀到另一個事務(wù)已提交的更新數(shù)據(jù)

例子:A和B事務(wù)并發(fā)執(zhí)行,A事務(wù)查詢數(shù)據(jù),然后B事務(wù)更新該數(shù)據(jù),A再次查詢該數(shù)據(jù)時,發(fā)現(xiàn)該數(shù)據(jù)變化了

4、覆蓋更新

這是不可重復(fù)讀中的特例,一個事務(wù)覆蓋另一個事務(wù)已提交的更新數(shù)據(jù)

例子:A事務(wù)更新數(shù)據(jù),然后B事務(wù)更新該數(shù)據(jù),A事務(wù)查詢發(fā)現(xiàn)自己更新的數(shù)據(jù)變了

5、虛讀(幻讀)

一個事務(wù)讀到另一個事務(wù)已提交的新插入的數(shù)據(jù)

例子:A和B事務(wù)并發(fā)執(zhí)行,A事務(wù)查詢數(shù)據(jù),B事務(wù)插入或者刪除數(shù)據(jù),A事務(wù)再次查詢發(fā)現(xiàn)結(jié)果集中有以前沒有的數(shù)據(jù)或者以前有的數(shù)據(jù)消失了

六、隔離級別

1、SERIALIZABLE(序列化)

一個事務(wù)在執(zhí)行過程中完全看不到其他事務(wù)對數(shù)據(jù)庫所做的更新,事務(wù)執(zhí)行的時候不允許別的事務(wù)并發(fā)執(zhí)行。完全串行化執(zhí)行,只能一個接著一個地執(zhí)行,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞

2、REPEATABLE READ(可重復(fù)讀)

一個事務(wù)在執(zhí)行過程中可以看到其他事務(wù)已經(jīng)提交的新插入的記錄,但是不能看到其他其他事務(wù)對已有記錄的更新

對于讀出的記錄,添加共享鎖直到transaction A結(jié)束。其它transaction B對這個記錄的試圖修改會一直等待直到transaction A結(jié)束

在同一個事務(wù)內(nèi)的查詢都是事務(wù)開始時刻一致的,InnoDB默認(rèn)級別。在SQL標(biāo)準(zhǔn)中,該隔離級別消除了不可重復(fù)讀,但是還存在幻讀

3、READ COMMITTED(提交讀)

一個事務(wù)在執(zhí)行過程中可以看到其他事務(wù)已經(jīng)提交的新插入的記錄,而且能看到其他事務(wù)已經(jīng)提交的對已有記錄的更新

在transaction A中讀取數(shù)據(jù)時對記錄添加共享鎖,但讀取結(jié)束立即釋放。其它transaction B對這個記錄的試圖修改會一直等待直到A中的讀取過程結(jié)束,而不需要整個transaction A的結(jié)束。所以,在transaction A的不同階段對同一記錄的讀取結(jié)果可能是不同的。

可能發(fā)生的問題:不可重復(fù)讀

4、READ UNCOMMITTED(未提交讀)

一個事務(wù)在執(zhí)行過程中可以看到其他事務(wù)沒有提交的新插入的記錄,而且能看到其他事務(wù)沒有提交的對已有記錄的更新

不添加共享鎖。所以其它transaction B可以在transaction A對記錄的讀取過程中修改同一記錄,可能會導(dǎo)致A讀取的數(shù)據(jù)是一個被破壞的或者說不完整不正確的數(shù)據(jù)。

另外,在transaction A中可以讀取到transaction B(未提交)中修改的數(shù)據(jù)。比如transaction B對R記錄修改了,但未提交。此時,在transaction A中讀取R記錄,讀出的是被B修改過的數(shù)據(jù)。

隔離級別臟讀(Dirty Read)不可重復(fù)讀(NonRepeatable Read)幻讀(Phantom Read)
未提交讀(Read uncommitted)可能可能可能
已提交讀(Read committed)不可能可能可能
可重復(fù)讀(Repeatable read)不可能不可能可能
可串行化(Serializable )不可能不可能不可能

?

由于MySQL的InnoDB默認(rèn)是使用的RR級別,所以我們先要將該session開啟成RC級別,并且設(shè)置binlog的模式

mysql> select @@session.tx_isolation; +-----------------------+ | @@global.tx_isolation | +-----------------------+ | REPEATABLE-READ | +-----------------------+ SET sessionbinlog_format = 'ROW'; //MIXED

表結(jié)構(gòu)

CREATE TABLE `users` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,`age` tinyint(11) NOT NULL,PRIMARY KEY (`id`),KEY `id_age` (`age`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;INSERT INTO users VALUES \ ( 1 , 'Bob' , 27 ), \ ( 2 , 'Mike' , 7 ),\ ( 3 , 'Tony' , 40 ),\ ( 4 , 'Bill' , 21 ),\ ( 5 , 'Mark' , 18 );

幻讀

SET session transaction isolation level Repeatable read;

幻讀發(fā)生在當(dāng)兩個完全相同的查詢執(zhí)行時,第二次查詢所返回的結(jié)果集跟第一個查詢不相同。發(fā)生的情況:沒有范圍鎖

事務(wù)1事務(wù)2
SELECT * FROM users WHERE age BETWEEN 10 AND 30 ?
? INSERT INTO users VALUES ( 3 , 'Bob' , 27 );
SELECT * FROM users WHERE age BETWEEN 10 AND 30;

?

如何避免:實行序列化隔離模式,在任何一個低級別的隔離中都可能會發(fā)生。

不可重復(fù)讀

SET session transaction isolation level read committed;

在基于鎖的并行控制方法中,如果在執(zhí)行select時不添加讀鎖,就會發(fā)生不可重復(fù)讀問題。在多版本并行控制機(jī)制中,當(dāng)一個遇到提交沖突的事務(wù)需要回退但卻被釋放時,會發(fā)生不可重復(fù)讀問題。

事務(wù)1事務(wù)2
SELECT * FROM users WHERE id = 1; ?
? UPDATE users SET age = 21 WHERE id = 1 ;?
SELECT * FROM users WHERE id = 1; ?

?

在上面這個例子中,事務(wù)2提交成功,它所做的修改已經(jīng)可見。然而,事務(wù)1已經(jīng)讀取了一個其它的值。在序列化和可重復(fù)讀的隔離級別中,數(shù)據(jù)庫管理系統(tǒng)會返回舊值,即在被事務(wù)2修改之前的值。在提交讀和未提交讀隔離級別下,可能會返回被更新的值,這就是“不可重復(fù)讀”。

有兩個策略可以防止這個問題的發(fā)生:

1. 推遲事務(wù)2的執(zhí)行,直至事務(wù)1提交或者回退。這種策略在使用鎖時應(yīng)用。(悲觀鎖機(jī)制,比如用select for update為數(shù)據(jù)行加上一個排他鎖)

2. 而在多版本并行控制中,事務(wù)2可以被先提交。而事務(wù)1,繼續(xù)執(zhí)行在舊版本的數(shù)據(jù)上。當(dāng)事務(wù)1終于嘗試提交時,數(shù)據(jù)庫會檢驗它的結(jié)果是否和事務(wù)1、事務(wù)2順序執(zhí)行時一樣。如果是,則事務(wù)1提交成功。如果不是,事務(wù)1會被回退。(樂觀鎖機(jī)制)

臟讀

SET session transaction isolation level read uncommitted;

臟讀發(fā)生在一個事務(wù)A讀取了被另一個事務(wù)B修改,但是還未提交的數(shù)據(jù)。假如B回退,則事務(wù)A讀取的是無效的數(shù)據(jù)。這跟不可重復(fù)讀類似,但是第二個事務(wù)不需要執(zhí)行提交。?

事務(wù)1事務(wù)2
SELECT * FROM users WHERE id = 1; ?
? UPDATE users SET age = 21 WHERE id = 1
SELECT FROM users WHERE id = 1; ?

7、隔離級別vs 鎖持續(xù)時間

在基于鎖的并發(fā)控制中,隔離級別決定了鎖的持有時間。"C"-表示鎖會持續(xù)到事務(wù)提交。?"S"?–表示鎖持續(xù)到當(dāng)前語句執(zhí)行完畢。如果鎖在語句執(zhí)行完畢就釋放則另外一個事務(wù)就可以在這個事務(wù)提交前修改鎖定的數(shù)據(jù),從而造成混亂

隔離級別l寫操作讀操作范圍操作 (...where...)
未提交讀SSS
提交讀CSS
可重復(fù)讀CCS
可序列化CCC

?

?

參考文章

https://zh.wikipedia.org/wiki/%E4%BA%8B%E5%8B%99%E9%9A%94%E9%9B%A2

轉(zhuǎn)載于:https://www.cnblogs.com/chenpingzhao/p/5041970.html

總結(jié)

以上是生活随笔為你收集整理的【mysql】关于事务的隔离级别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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