成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試官:MySQL的可重復(fù)讀級(jí)別能解決幻讀問題嗎?

數(shù)據(jù)庫 MySQL
之前在深入了解數(shù)據(jù)庫理論的時(shí)候,了解到事務(wù)的不同隔離級(jí)別可能存在的問題。為了更好的理解所以在MySQL數(shù)據(jù)庫中測(cè)試復(fù)現(xiàn)這些問題。關(guān)于臟讀和不可重復(fù)讀在相應(yīng)的隔離級(jí)別下都很容易的復(fù)現(xiàn)了。

引言

之前在深入了解數(shù)據(jù)庫理論的時(shí)候,了解到事務(wù)的不同隔離級(jí)別可能存在的問題。為了更好的理解所以在MySQL數(shù)據(jù)庫中測(cè)試復(fù)現(xiàn)這些問題。關(guān)于臟讀和不可重復(fù)讀在相應(yīng)的隔離級(jí)別下都很容易的復(fù)現(xiàn)了。

但是對(duì)于幻讀,我發(fā)現(xiàn)在可重復(fù)讀的隔離級(jí)別下沒有出現(xiàn),當(dāng)時(shí)想到難道是MySQL對(duì)幻讀做了什么處理?

測(cè)試:

創(chuàng)建一張測(cè)試用的表dept: 

  1. CREATE TABLE `dept` (  
  2.   `id` int(11) NOT NULL AUTO_INCREMENT,  
  3.   `name` varchar(20) DEFAULT NULL,  
  4.   PRIMARY KEY (`id`)  
  5. ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8   
  6. insert into dept(name) values("后勤部") 

根據(jù)上面的流程執(zhí)行,預(yù)期來說應(yīng)該是事務(wù)1的第一條select查詢出一條數(shù)據(jù),第二個(gè)select查詢出兩條數(shù)據(jù)(包含事務(wù)2提交的數(shù)據(jù))。

但是在實(shí)際測(cè)試中發(fā)現(xiàn)第二條select實(shí)際上也只查詢處理一條數(shù)據(jù)。這是但是根據(jù)數(shù)據(jù)庫理論的可重復(fù)讀的實(shí)現(xiàn)(排他鎖和共享鎖)這是不應(yīng)該的情況。

在了解實(shí)際原因前我們先復(fù)習(xí)下事務(wù)的相關(guān)理論。

數(shù)據(jù)庫原理理論

事務(wù)

事務(wù)(Transaction),一般是指要做的或所做的事情。在計(jì)算機(jī)術(shù)語中是指訪問并可能更新數(shù)據(jù)庫中各種數(shù)據(jù)項(xiàng)的一個(gè)程序執(zhí)行單元(unit)。事務(wù)由事務(wù)開始(begin transaction)和事務(wù)結(jié)束(end transaction)之間執(zhí)行的全體操作組成。

在關(guān)系數(shù)據(jù)庫中,一個(gè)事務(wù)可以是一組SQL語句或整個(gè)程序。

為什么要有事務(wù)

一個(gè)數(shù)據(jù)庫事務(wù)通常包含對(duì)數(shù)據(jù)庫進(jìn)行讀或?qū)懙囊粋€(gè)操作序列。它的存在包含有以下兩個(gè)目的:

  •  為數(shù)據(jù)庫操作提供了一個(gè)從失敗中恢復(fù)到正常狀態(tài)的方法,同時(shí)提供了數(shù)據(jù)庫在異常狀態(tài)下仍能保持一致性的方法。
  •  當(dāng)多個(gè)應(yīng)用程序在并發(fā)訪問數(shù)據(jù)庫時(shí),可以在這些應(yīng)用程序之間提供一個(gè)隔離方法,保證彼此的操作互相干擾。

事務(wù)特性

事務(wù)具有4個(gè)特性:原子性、一致性、隔離性、持久性。這四個(gè)屬性通常稱為 ACID 特性。

  •  原子性(atomicity):一個(gè)事務(wù)應(yīng)該是一個(gè)不可分割的工作單位,事務(wù)中包括的操作要么都成功,要么都不成功。
  •  一致性(consistency):事務(wù)必須是使數(shù)據(jù)庫從一個(gè)一致性狀態(tài)變到另一個(gè)一致性狀態(tài)。一致性與原子性是密切相關(guān)的。
  •  隔離性(isolation):一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)干擾。即一個(gè)事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)在事務(wù)未提交前對(duì)并發(fā)的其他事務(wù)是隔離的,并發(fā)執(zhí)行的各個(gè)事務(wù)之間不能互相影響。
  •  持久性(durability):一個(gè)事務(wù)一旦成功提交,它對(duì)數(shù)據(jù)庫中數(shù)據(jù)的改變就應(yīng)該是永久性的。接下來的其他操作或故障不應(yīng)該對(duì)其有任何影響。

事務(wù)之間的幾個(gè)特性并不是一組同等的概念:

如果在任何時(shí)刻都只有一個(gè)事務(wù),那么其天然是具有隔離性的,這時(shí)只要保證原子性就能具有一致性。

如果存在并發(fā)的情況下,就需要保證原子性和隔離性才能保證一致性。

數(shù)據(jù)庫并發(fā)事務(wù)中存在的問題

如果不考慮事務(wù)的隔離性,會(huì)發(fā)生以下幾種問題:

臟讀

臟讀是指在一個(gè)事務(wù)處理過程里讀取了另一個(gè)未提交的事務(wù)中的數(shù)據(jù)。當(dāng)一個(gè)事務(wù)正在多次修改某個(gè)數(shù)據(jù),而在這個(gè)事務(wù)中這多次的修改都還未提交,這時(shí)一個(gè)并發(fā)的事務(wù)來訪問該數(shù)據(jù),就會(huì)造成兩個(gè)事務(wù)得到的數(shù)據(jù)不一致。

不可重復(fù)讀

不可重復(fù)讀是指在對(duì)于數(shù)據(jù)庫中的某條數(shù)據(jù),一個(gè)事務(wù)范圍內(nèi)多次查詢返回不同的數(shù)據(jù)值(這里不同是指某一條或多條數(shù)據(jù)的內(nèi)容前后不一致,但數(shù)據(jù)條數(shù)相同),這是由于在查詢間隔,該事務(wù)需要用到的數(shù)據(jù)被另一個(gè)事務(wù)修改并提交了。

不可重復(fù)讀和臟讀的區(qū)別是,臟讀是某一事務(wù)讀取了另一個(gè)事務(wù)未提交的臟數(shù)據(jù),而不可重復(fù)讀則是讀取了其他事務(wù)提交的數(shù)據(jù)。需要注意的是在某些情況下不可重復(fù)讀并不是問題。

幻讀

幻讀是事務(wù)非獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象。例如事務(wù)T1對(duì)一個(gè)表中所有的行的某個(gè)數(shù)據(jù)項(xiàng)做了從“1”修改為“2”的操作,這時(shí)事務(wù)T2又對(duì)這個(gè)表中插入了一行數(shù)據(jù)項(xiàng),而這個(gè)數(shù)據(jù)項(xiàng)的數(shù)值還是為“1”并且提交給數(shù)據(jù)庫。

而操作事務(wù)T1的用戶如果再查看剛剛修改的數(shù)據(jù),會(huì)發(fā)現(xiàn)還有一行沒有修改,其實(shí)這行是從事務(wù)T2中添加的,就好像產(chǎn)生幻覺一樣,這就是發(fā)生了幻讀。

幻讀和不可重復(fù)讀都是讀取了另一條已經(jīng)提交的事務(wù)(這點(diǎn)就臟讀不同),所不同的是不可重復(fù)讀可能發(fā)生在update,delete操作中,而幻讀發(fā)生在insert操作中。

排他鎖,共享鎖

排它鎖(Exclusive),又稱為X 鎖,寫鎖。

共享鎖(Shared),又稱為S 鎖,讀鎖。

讀寫鎖之間有以下的關(guān)系:

  •  一個(gè)事務(wù)對(duì)數(shù)據(jù)對(duì)象O加了 S 鎖,可以對(duì) O進(jìn)行讀取操作,但是不能進(jìn)行更新操作。加鎖期間其它事務(wù)能對(duì)O 加 S 鎖,但是不能加 X 鎖。
  •  一個(gè)事務(wù)對(duì)數(shù)據(jù)對(duì)象 O 加了 X 鎖,就可以對(duì) O 進(jìn)行讀取和更新。加鎖期間其它事務(wù)不能對(duì) O 加任何鎖。

即讀寫鎖之間的關(guān)系可以概括為:多讀單寫

事務(wù)的隔離級(jí)別

在事務(wù)中存在以下幾種隔離級(jí)別:

讀未提交(Read Uncommitted)

解決更新丟失問題。如果一個(gè)事務(wù)已經(jīng)開始寫操作,那么其他事務(wù)則不允許同時(shí)進(jìn)行寫操作,但允許其他事務(wù)讀此行數(shù)據(jù)。該隔離級(jí)別可以通過“排他寫鎖”實(shí)現(xiàn),即事務(wù)需要對(duì)某些數(shù)據(jù)進(jìn)行修改必須對(duì)這些數(shù)據(jù)加 X 鎖,讀數(shù)據(jù)不需要加 S 鎖。

讀已提交(Read Committed)

解決了臟讀問題。讀取數(shù)據(jù)的事務(wù)允許其他事務(wù)繼續(xù)訪問該行數(shù)據(jù),但是未提交的寫事務(wù)將會(huì)禁止其他事務(wù)訪問該行。這可以通過“瞬間共享讀鎖”和“排他寫鎖”實(shí)現(xiàn), 即事務(wù)需要對(duì)某些數(shù)據(jù)進(jìn)行修改必須對(duì)這些數(shù)據(jù)加 X 鎖,讀數(shù)據(jù)時(shí)需要加上 S 鎖,當(dāng)數(shù)據(jù)讀取完成后立刻釋放 S 鎖,不用等到事務(wù)結(jié)束。

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

禁止不可重復(fù)讀取和臟讀取,但是有時(shí)可能出現(xiàn)幻讀數(shù)據(jù)。讀取數(shù)據(jù)的事務(wù)將會(huì)禁止寫事務(wù)(但允許讀事務(wù)),寫事務(wù)則禁止任何其他事務(wù)。

Mysql默認(rèn)使用該隔離級(jí)別。這可以通過“共享讀鎖”和“排他寫鎖”實(shí)現(xiàn),即事務(wù)需要對(duì)某些數(shù)據(jù)進(jìn)行修改必須對(duì)這些數(shù)據(jù)加 X 鎖,讀數(shù)據(jù)時(shí)需要加上 S 鎖,當(dāng)數(shù)據(jù)讀取完成并不立刻釋放 S 鎖,而是等到事務(wù)結(jié)束后再釋放。

串行化(Serializable)

解決了幻讀的問題的。提供嚴(yán)格的事務(wù)隔離。它要求事務(wù)序列化執(zhí)行,事務(wù)只能一個(gè)接著一個(gè)地執(zhí)行,不能并發(fā)執(zhí)行。僅僅通過“行級(jí)鎖”是無法實(shí)現(xiàn)事務(wù)序列化的,必須通過其他機(jī)制保證新插入的數(shù)據(jù)不會(huì)被剛執(zhí)行查詢操作的事務(wù)訪問到。

MySQL中的隔離級(jí)別的實(shí)現(xiàn)

上面的內(nèi)容解釋了一些數(shù)據(jù)庫理論的概念,但是在MySQL、ORACLE這樣的數(shù)據(jù)庫中,為了性能的考慮并不是完全按照上面介紹的理論來實(shí)現(xiàn)的。

MVCC

多版本并發(fā)控制(Multi-Version Concurrency Control, MVCC)是MySQL中基于樂觀鎖理論實(shí)現(xiàn)隔離級(jí)別的方式,用于實(shí)現(xiàn)讀已提交和可重復(fù)讀取隔離級(jí)別的實(shí)現(xiàn)。

實(shí)現(xiàn)(隔離級(jí)別為可重復(fù)讀)

在說到如何實(shí)現(xiàn)前先引入兩個(gè)概念:

  •  系統(tǒng)版本號(hào):一個(gè)遞增的數(shù)字,每開始一個(gè)新的事務(wù),系統(tǒng)版本號(hào)就會(huì)自動(dòng)遞增。
  •  事務(wù)版本號(hào):事務(wù)開始時(shí)的系統(tǒng)版本號(hào)。

在MySQL中,會(huì)在表中每一條數(shù)據(jù)后面添加兩個(gè)字段:

  •  創(chuàng)建版本號(hào):創(chuàng)建一行數(shù)據(jù)時(shí),將當(dāng)前系統(tǒng)版本號(hào)作為創(chuàng)建版本號(hào)賦值
  •  刪除版本號(hào):刪除一行數(shù)據(jù)時(shí),將當(dāng)前系統(tǒng)版本號(hào)作為刪除版本號(hào)賦值

SELECT

select時(shí)讀取數(shù)據(jù)的規(guī)則為:創(chuàng)建版本號(hào)<=當(dāng)前事務(wù)版本號(hào),刪除版本號(hào)為空或>當(dāng)前事務(wù)版本號(hào)。

創(chuàng)建版本號(hào)<=當(dāng)前事務(wù)版本號(hào)保證取出的數(shù)據(jù)不會(huì)有后啟動(dòng)的事務(wù)中創(chuàng)建的數(shù)據(jù)。這也是為什么在開始的示例中我們不會(huì)查出后來添加的數(shù)據(jù)的原因

刪除版本號(hào)為空或>當(dāng)前事務(wù)版本號(hào)保證了至少在該事務(wù)開啟之前數(shù)據(jù)沒有被刪除,是應(yīng)該被查出來的數(shù)據(jù)。

INSERT

insert是將當(dāng)前的系統(tǒng)版本號(hào)賦值給創(chuàng)建版本號(hào)字段。

UPDATE

插入一條新記錄,保存當(dāng)前事務(wù)版本號(hào)為行創(chuàng)建版本號(hào),同時(shí)保存當(dāng)前事務(wù)版本號(hào)到原來刪除的行,實(shí)際上這里的更新是通過delete和insert實(shí)現(xiàn)的。

DELETE

刪除時(shí)將當(dāng)前的系統(tǒng)版本號(hào)賦值給刪除版本號(hào)字段,標(biāo)識(shí)該行數(shù)據(jù)在那一個(gè)事務(wù)中會(huì)被刪除,即使實(shí)際上在位commit時(shí)該數(shù)據(jù)沒有被刪除。根據(jù)select的規(guī)則后開啟的數(shù)據(jù)也不會(huì)查詢到該數(shù)據(jù)。

MVCC真的解決了幻讀?

從最開始我們的測(cè)試示例和上面的理論支持來看貌似在MySQL中通過MVCC就解決了幻讀的問題,那既然這樣串行化讀貌似就沒啥意義了,帶著疑問繼續(xù)測(cè)試。

測(cè)試前數(shù)據(jù):

根據(jù)上面的結(jié)果我們期望的結(jié)果是這樣的:

id name
1 財(cái)務(wù)部
2 研發(fā)部

但是實(shí)際上我們的經(jīng)過是:

本來我們希望得到的結(jié)果只是第一條數(shù)據(jù)的部門改為財(cái)務(wù),但是結(jié)果確實(shí)兩條數(shù)據(jù)都被修改了。

這種結(jié)果告訴我們其實(shí)在MySQL可重復(fù)讀的隔離級(jí)別中并不是完全解決了幻讀的問題,而是解決了讀數(shù)據(jù)情況下的幻讀問題。而對(duì)于修改的操作依舊存在幻讀問題,就是說MVCC對(duì)于幻讀的解決時(shí)不徹底的。

快照讀和當(dāng)前讀

出現(xiàn)了上面的情況我們需要知道為什么會(huì)出現(xiàn)這種情況。在查閱了一些資料后發(fā)現(xiàn)在RR級(jí)別中,通過MVCC機(jī)制,雖然讓數(shù)據(jù)變得可重復(fù)讀,但我們讀到的數(shù)據(jù)可能是歷史數(shù)據(jù),不是數(shù)據(jù)庫最新的數(shù)據(jù)。

這種讀取歷史數(shù)據(jù)的方式,我們叫它快照讀 (snapshot read),而讀取數(shù)據(jù)庫最新版本數(shù)據(jù)的方式,叫當(dāng)前讀 (current read)。

select 快照讀

當(dāng)執(zhí)行select操作是innodb默認(rèn)會(huì)執(zhí)行快照讀,會(huì)記錄下這次select后的結(jié)果,之后select 的時(shí)候就會(huì)返回這次快照的數(shù)據(jù),即使其他事務(wù)提交了不會(huì)影響當(dāng)前select的數(shù)據(jù),這就實(shí)現(xiàn)了可重復(fù)讀了。

快照的生成當(dāng)在第一次執(zhí)行select的時(shí)候,也就是說假設(shè)當(dāng)A開啟了事務(wù),然后沒有執(zhí)行任何操作,這時(shí)候B insert了一條數(shù)據(jù)然后commit,這時(shí)候A執(zhí)行 select,那么返回的數(shù)據(jù)中就會(huì)有B添加的那條數(shù)據(jù)。

之后無論再有其他事務(wù)commit都沒有關(guān)系,因?yàn)榭煺找呀?jīng)生成了,后面的select都是根據(jù)快照來的。

當(dāng)前讀

對(duì)于會(huì)對(duì)數(shù)據(jù)修改的操作(update、insert、delete)都是采用當(dāng)前讀的模式。在執(zhí)行這幾個(gè)操作時(shí)會(huì)讀取最新的記錄,即使是別的事務(wù)提交的數(shù)據(jù)也可以查詢到。

假設(shè)要update一條記錄,但是在另一個(gè)事務(wù)中已經(jīng)delete掉這條數(shù)據(jù)并且commit了,如果update就會(huì)產(chǎn)生沖突,所以在update的時(shí)候需要知道最新的數(shù)據(jù)。也正是因?yàn)檫@樣所以才導(dǎo)致上面我們測(cè)試的那種情況。

select的當(dāng)前讀需要手動(dòng)的加鎖: 

  1. select * from table where ? lock in share mode;  
  2. select * from table where ? for update; 

有個(gè)問題說明下

在測(cè)試過程中最開始我以為使用begin語句就是開始一個(gè)事務(wù)了,所以在上面第二次測(cè)試中因?yàn)橄乳_始的事務(wù)1,結(jié)果在事務(wù)1中卻查到了事務(wù)2新增的數(shù)據(jù),當(dāng)時(shí)認(rèn)為這和前面MVCC中的select的規(guī)則不一致了,所以做了如下測(cè)試:

 

  1. SELECT * FROM information_schema.INNODB_TRX //用于查詢當(dāng)前正在執(zhí)行中的事務(wù) 

可以看到如果只是執(zhí)行begin語句實(shí)際上并沒有開啟一個(gè)事務(wù)。

下面在begin后添加一條select語句:

所以要明白實(shí)際上是對(duì)數(shù)據(jù)進(jìn)行了增刪改查等操作后才開啟了一個(gè)事務(wù)。

如何解決幻讀

很明顯可重復(fù)讀的隔離級(jí)別沒有辦法徹底的解決幻讀的問題,如果我們的項(xiàng)目中需要解決幻讀的話也有兩個(gè)辦法:

  •  使用串行化讀的隔離級(jí)別
  •  MVCC+next-key locks:next-key locks由record locks(索引加鎖) 和 gap locks(間隙鎖,每次鎖住的不光是需要使用的數(shù)據(jù),還會(huì)鎖住這些數(shù)據(jù)附近的數(shù)據(jù))

實(shí)際上很多的項(xiàng)目中是不會(huì)使用到上面的兩種方法的,串行化讀的性能太差,而且其實(shí)幻讀很多時(shí)候是我們完全可以接受的。 

 

責(zé)任編輯:龐桂玉 來源: Java知音
相關(guān)推薦

2024-05-13 11:46:33

MySQL數(shù)據(jù)庫

2023-11-01 14:13:00

MySQL事務(wù)隔離級(jí)別

2024-03-11 00:00:00

mysqlInnoDB幻讀

2022-06-29 11:01:05

MySQL事務(wù)隔離級(jí)別

2023-10-26 00:41:46

臟讀數(shù)據(jù)幻讀

2024-04-19 08:18:47

MySQLSQL隔離

2023-02-02 07:06:10

2022-01-03 07:18:05

臟讀幻讀 MySQL

2024-04-24 08:26:35

事務(wù)數(shù)據(jù)InnoDB

2022-09-21 09:00:10

MySQL幻讀隔離級(jí)別

2023-08-09 17:22:30

MVCCMySQL數(shù)據(jù)

2020-07-02 08:22:56

MySQL間隙鎖過行鎖

2010-09-30 16:21:40

DB2隔離級(jí)別

2019-03-21 09:06:00

數(shù)據(jù)庫復(fù)讀幻讀

2022-04-27 07:32:02

臟讀幻讀不可重復(fù)讀

2024-07-16 08:19:46

MySQL數(shù)據(jù)InnoDB

2021-06-11 16:59:41

MySQLRepeatableRead

2021-08-02 09:01:05

MySQL 多版本并發(fā)數(shù)據(jù)庫

2022-06-30 08:00:00

MySQL關(guān)系數(shù)據(jù)庫開發(fā)

2021-07-26 10:28:13

MySQL事務(wù)隔離
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 亚洲电影第三页 | 久久久精品一区二区 | 亚洲精品二三区 | 日本视频中文字幕 | 日韩在线视频免费观看 | 91色网站| 久久综合久久综合久久综合 | 久久久久亚洲精品 | a毛片| 久久精品成人 | 三级免费毛片 | 亚洲一区视频在线播放 | 欧洲免费视频 | 国产一区二区视频免费在线观看 | 日本精品久久久久 | 亚洲免费观看 | 日韩高清电影 | 国产免费福利 | 国产日韩精品一区二区三区 | 久久www免费人成看片高清 | 精品久久久久一区二区国产 | 国产乱人伦精品一区二区 | 黄色一级片aaa | 性高湖久久久久久久久aaaaa | 一级视频在线免费观看 | 日韩久久中文字幕 | 美女激情av | 91精品国产综合久久婷婷香蕉 | 日本欧美国产在线观看 | 欧美激情一区二区三区 | 亚洲成人一区 | 亚洲免费婷婷 | av中文在线观看 | 亚洲区一区二 | 一区二区三区在线播放视频 | 浮生影院免费观看中文版 | 99精品一区| 蜜桃精品视频在线 | 久久成人久久 | www日本高清 | 欧美日韩一区二区三区视频 |