中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

什么是臟讀與幻讀

發布時間:2021-10-09 17:16:14 來源:億速云 閱讀:154 作者:iii 欄目:數據庫

這篇文章主要講解了“什么是臟讀與幻讀”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“什么是臟讀與幻讀”吧!

什么是臟讀與幻讀

select @@tx_isolation;

什么是臟讀與幻讀

MySQL就包含4種隔離級別,隔離的當然是數據。要修改隔離級別的話,可以使用下面的SQL語句。

set session transaction isolation level read uncommitted; set session transaction isolation level read committed; set session transaction isolation level repeatable read; set session transaction isolation level serializable;

ok,我們創建一張小小的測試表,來看一下并發環境下的魔幻效果。

CREATE TABLE `xjjdog_tx` (  `id` INT(11) NOT NULL,  `name` VARCHAR(50) NOT NULL COLLATE 'utf8_general_ci',  `money` BIGINT(20) NOT NULL DEFAULT '0',  PRIMARY KEY (`id`) USING BTREE ) COLLATE='utf8_general_ci' ENGINE=InnoDB ; INSERT INTO `xjjdog_tx` (`id`, `name`, `money`) VALUES (2, 'xjjdog1', 100); INSERT INTO `xjjdog_tx` (`id`, `name`, `money`) VALUES (1, 'xjjdog0', 100);

1. 臟讀

臟讀,意思就是讀出了臟數據。啥叫臟數據?就是另外一個事務還沒有提交的數據。在read  uncommitted隔離級別下,就會出現臟讀。比如下面這個時序

事務 A:set session transaction isolation level read uncommitted; 事務 B:set session transaction isolation level read uncommitted; 事務 A:START TRANSACTION ; 事務 B:START TRANSACTION ; 事務 A:UPDATE xjjdog_tx SET money=money+100 WHERE NAME='xjjdog0'; 事務 B:UPDATE xjjdog_tx SET money=money+100 WHERE NAME='xjjdog0'; 事務 A:ROLLBACK ; 事務 B:COMMIT ; 事務 B:SELECT * FROM xjjdog_tx ;

在這個場景下,money的原始值為100,分別在兩個session中進行了加100的操作,然后回滾了其中的一個session事務。結果,經過查詢,發現money的值保持100不變。也就是其中一次加100的操作被覆蓋掉了。

什么是臟讀與幻讀

所以臟讀發生有幾個條件。

  • 高并發場景,在一個事務A開始之后還沒結束之前,有另外一個事務參與了事務A所涉及的數據行讀寫

  • 事務隔離級別處于最低的讀未提交

  • 在你使用到這些數據之后,事務A回滾,造成你之前拿到的數據已經不再存在

解決方式,只需要設置成隔離級別比read uncommitted高即可。

2. 不可重復讀

把隔離級別設置成read  committed即可避免臟讀,這其實非常好理解。臟讀產生的根本原因就是在事務的執行期間有別的操作亂入,這個隔離級別要求事務A提交之后,修改后的值,才能被事務B讀到,所以臟讀是不可能會發生的,從根本上杜絕了。

但read commited會發生不可重復讀的情況。

顧名思義,就是在一個事務周期內,對于一個值的讀取,產生了兩個結果。

不可重復讀,證明了世界并不是總圍繞著你轉的。在你的事務執行期間,會有無數的其他事務執行,如果你的事務持續時間超過了這些事務,那么你就可能讀到兩個或者更多的值。

讓我來給你講一個故事。

從前,有一顆桃樹,長了12棵桃子。有一只猴子,叫做xjjdog,它想吃上面的桃子,但桃子還不熟。

第二天去看的時候,它發現桃子少了一個,變成了11個,經過仔細打聽,原來是被猴子A搶先吃掉一個。

第二天去看的時候,桃子又少了一個,變成了10個,原來是被饞嘴的猴子B吃掉一個。

如此這般,桃子一天天少了下去,只剩下最后的2個了,但桃子還是沒熟。

再不摘桃子就沒了,xjjdog摘下了最后的2個桃子,正打算大快朵頤,結果跳出一只猴子X,說我盯著這些桃子已經1年了...

在這故事中,猴子A、B的事務持續周期是1天;xjjdog的事務持續周期是直到桃子成熟;猴子X的持續周期更長,可能是一年。它們每天看到的桃子,并不總是12個。今天的桃子,可能被其他的猴子(事務)給吃掉了,造成了觀測的結果是不一樣的,這就是不可重復讀的概念。

有時候,即使讀到的值是一樣的,也不能證明沒問題。比如有財務挪用了2億去炒股,然后在月底把2億還了回來,雖然最終的金額都是一致的,但由于你的對賬周期長,就發現不了這種差異。

如何解決不可重復讀呢?先要看一下不可重復讀是不是問題。

有的系統,要求的就是這樣的邏輯,每次在事務中讀取到不一樣的值,它是可以忍受的。但如果你想要在桃子成熟之前,桃子的數量都在你的掌控之中,那不可重復讀就是一種問題。

一種非常好的方式,就是xjjdog一直站在桃樹地下。當有別的猴子想要摘桃,就把它趕走。這種方式可行,但在數據庫中非常低效,這是serializable級別的做法。

MySQL有一個默認的事務隔離級別,叫做repeatable read,使用了MVCC的方式(innodb),要更輕量級一些。

3. 可重復讀

這就是MVCC(Multi-Version Concurrency Control)的功勞了,它有三個特點。

每行數據都存在一個版本,每次數據更新時都更新該版本

修改時,拷貝一份,當前版本隨意修改,事務之間無干擾

保存時比較版本號,如果成功commit覆蓋原記錄,失敗則rollback

MVCC在InnoDB中的實現主要是為了提高數據庫并發性能,用更好的方式去處理讀-寫沖突,做到即使有讀寫沖突時,也能做到不加鎖,非阻塞并發讀。它的實現關鍵也有三項技術:

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. 3個隱式字段:DB_TRX_ID,最近修改它的事務ID;DB_ROLL_PTR,回滾指針,指向上一個版本;DB_ROW_ID,隱藏主鍵

  3. undo日志:的對同一記錄的修改,會生成針對此記錄的版本變更鏈表

  4. read view:快照讀操作的時候,產生的讀視圖。除了使用上面的額外信息,它也會維護一個活躍的事務ID集合

一切的關鍵,就在于快照這兩個字上面。

比如事務A對某個記錄進行了快照讀,那么在快照讀的這一刻,就生成了一個Read  View。在這一刻,事務B和C,還沒有commit,事務D和E,在建立ReadView那一刻之前,commit完成,那么這個Read  View,就不能夠讀到B和C的修改。

但可惜的是,可重復讀,只能解決快照讀的不可重復讀,快照讀的時機,也會影響讀取的準確程度。請看下面兩種情況。

下面這種情況讀到的是500。

事務A事務B
開啟事務開啟事務
快照讀(無影響)查詢金額為500快照讀查詢金額為500
更新金額為400 
提交事務 
 select 快照讀金額為500
 select lock in share mode當前讀金額為400

下面這種情況讀到的是400。

事務A事務B
開啟事務開啟事務
快照讀(無影響)查詢金額為500 
更新金額為400 
提交事務 
 select 快照讀金額為400
 select lock in share mode當前讀金額為400
 

(表格來自[SnailMann]的博客)。

4. 幻讀

幻讀,這個詞本身就非常的迷幻。在RU、RC、RR級別下,都會出現幻讀。

拿一個最簡單的例子來說。讓你select一條記錄是否存在然后打算進行后續插入時,如果這條記錄不存在,然后你執行了插入操作,但在實際執行插入操作的時候,結果卻報錯了,這條記錄已經存在了,這就是幻讀。

首先,確認目前時可重復讀級別。如果不是,則修改之。

SELECT @@tx_isolation # set session transaction isolation level repeatable read

讓我們來看一下這個靈異過程。

什么是臟讀與幻讀

有5個步驟,我都給你標好了。下面一一介紹。

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. 事務A使用begin開啟一個事務,然后查詢id為3的記錄,此時不存在。但由于快照讀開啟了一個針對于id為3的記錄的read  view,所以在這個事務自始至終都不能夠讀到為3的記錄。很好,這就是我們不可重復讀所需要的

  3. 接下來,事務B插入了一條id為3的記錄,并提交成功

  4. 事務A此時也想插入這條記錄,于是執行了相同的插入操作,結果數據庫報錯,顯示這條記錄已經存在

  5. 事務A此時一臉懵逼,想看一下這條記錄到底是啥,但當它再次執行select語句的時候,卻查不到這條記錄

  6. 但在其他事務中,是可以看到這條記錄的,因為它已經正確提交

這就是幻讀。

5. 如何解決幻讀

幻讀有錯么?多數情況下沒錯,就是報錯怪異了些。要防止幻讀,需要開啟FOR UPDATE這樣高強度的鎖定,實際情況是非常少用。

為什么上面的操作,insert能報錯,但select卻無法查到數據呢?這就不得不提一下數據庫讀的兩種模式:

快照讀:普通的select操作,是從read view中讀取數據,讀取的可能是歷史數據

當前讀:insert、update、delete、select..for update這種操作,讀取的總是當前的最新數據

對于當前讀,你讀取的行,以及行的間隙都會被加鎖,直到事務提交時才會釋放,其他的事務無法進行修改,所以也不會出現不可重復讀、幻讀的情形。所以insert能夠發現沖突,而普通select卻不可以。要想解決幻讀,就需要加X鎖。在上面這種情況,就可以在事務A中執行:

SELECT * FROM xjjdog_tx WHERE id=3 FOR UPDATE

當這么做的時候,即使id為3的記錄不存在,它也會創建鎖(在背后可能根據記錄的存在與否加行X鎖或者next-key lock間隙x鎖)。

感謝各位的閱讀,以上就是“什么是臟讀與幻讀”的內容了,經過本文的學習后,相信大家對什么是臟讀與幻讀這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

韩城市| 延庆县| 精河县| 新和县| 密山市| 鄂托克旗| 玛沁县| 房产| 当雄县| 衡东县| 永嘉县| 巴里| 屏山县| 额济纳旗| 正阳县| 丰都县| 长乐市| 白水县| 女性| 济阳县| 杭锦旗| 彝良县| 顺昌县| 库车县| 巴彦县| 安吉县| 乳源| 萨嘎县| 德令哈市| 丘北县| 漯河市| 汨罗市| 福安市| 图木舒克市| 咸阳市| 凤凰县| 贞丰县| 绍兴县| 简阳市| 乌兰察布市| 四川省|