1. 程式人生 > >跟面試官侃半小時MySQL事務隔離性,從基本概念深入到實現

跟面試官侃半小時MySQL事務隔離性,從基本概念深入到實現

提到MySQL的事務,我相信對MySQL有了解的同學都能聊上幾句,無論是面試求職,還是日常開發,MySQL的事務都跟我們息息相關。

而事務的ACID(即原子性Atomicity、一致性Consistency、隔離性Isolation、永續性Durability)可以說涵蓋了事務的全部知識點,所以,我們不僅要知道ACID是什麼,還要了解ACID背後的實現,只有這樣,無論在日常開發還是面試求職,都能無往而不利。

為了大家更好的閱讀體驗,對ACID的深入分析將分為上下兩篇。

本篇為上篇,主要圍繞ACID中的I,也就是“隔離性”展開,從基本概念,到隔離性的實現,最後以一個實戰案例進行融會貫通。

嗯,看完你都能理解,那跟面試官侃半小時隔離性就沒問題了。

1.事務隔離性的基本概念

1.1 什麼是ACID中的Isolation,隔離性

Isolation,隔離性,也有人稱之為併發控制(concurrency control)。事務的隔離性要求每個事務讀寫的物件對其他事務都是相互隔離的,也就是這個事務提交前,這個事務的修改內容對其他事務都是不可見的。事務的隔離性,主要是解決不同事物之間的相互讀寫影響。

所謂的讀寫影響注意分為三種:

  • 髒讀:讀到了別的事務尚未提交(commit)的變更,別人沒提交,我讀到了。
  • 不可重複讀:別的事務提交了變更,被當前事務讀到了。然後導致本事務多次select的結果不一樣,讀到了別的事務提交的內容。
  • 幻讀:也是讀到了別的事務提交的內容,但是跟上面的不同之處在於,讀到了原本不存在的記錄。

注意,不可重複讀,主要是讀到了別的事務update的內容。而幻讀,是讀到了別的事務insert的內容。

1.2 隔離性的隔離級別

為了解決事務隔離性的問題,資料庫一般會有不同的隔離級別來解決相應的讀寫影響。

  • 讀未提交:一個事務B還沒提交,它的修改就被別的事務A讀到了。
  • 讀已提交:一個事務B提交後,它的修改被其他事務A看到了。
  • 可重複讀:一個事物B提交前和提交後,事務A都無法讀到事務B的變更。
  • 序列化:對同一行記錄,當出現不同事物的讀寫衝突時,是通過序列化的方式解決的,後一個事務必須等前一個事務完成才能執行。

不同隔離級別能夠解決不同的隔離性問題。

 

需要注意的是,這是標準事務隔離級別的定義。在MySQL的innodb引擎中,在可重複讀級別下,通過mvcc解決了幻讀的問題,具體實現我們後面再講。

同時,需要注意的是,到目前為止,我們說的讀,都是”快照讀”,普通的select。後面我們還會提到“當前讀”,是不一樣的哦。

2.事務隔離性的實現

要實現事務的隔離性,需要了解兩個方面的內容,一個是鎖,一個是多版本併發控制(MVCC)。

2.1 事務的行鎖

InnoDB中,實現了兩種標準的行級鎖:

  • 共享鎖(S Lock),也叫讀鎖,允許事務讀取一行資料。
  • 排它鎖(X Lock),也叫寫鎖,允許事務刪除或者更新一行資料(注意,這裡沒有提到插入哦,插入涉及到幻讀,可以看文章最後的說明)

普通select語句不會有任何鎖,那麼如何獲得共享鎖和排它鎖呢?

  • Select … lock in share mode語句能夠獲得共享鎖
  • Select … for update(特殊的select,用mysql簡單實現分散式鎖經常用它)、Update、delete語句能夠獲得排它鎖

當一個事務A已經獲得了行r的共享鎖,那麼另一個事務B可以立刻獲得行r的共享鎖,因為不會改變r的數值,這種叫做鎖相容。

如果這時候有事務C希望獲得行r的排它鎖,那麼就必須等待事務A和事務B釋放行r的共享鎖之後,才能獲得排它鎖,這種叫做鎖不相容。

 

普通的select不會對行上鎖,而select…lock in share mode會上共享鎖,select…for update會上排它鎖。

  • 對於普通的select的讀取方式,稱為”快照讀“,也叫”一致性非鎖定讀“。
  • 對於帶鎖的select讀取,或者update tb set a = a+1(讀取a的當前值),稱為“當前讀”,也叫“一致性鎖定讀”。

如果在update、insert的時候,不能進行select,那麼服務的併發訪問效能就太差了。因此,我們日常的查詢,都是“快照讀”,不會上鎖,只有在update\insert\“當前讀”的時候,才會上鎖。而為了解決“快照讀”的併發訪問問題,就引入了MVCC。

2.2 多版本併發控制MVCC

如果說上面的行鎖是一種悲觀鎖,那麼MVCC就是一種樂觀鎖的實現方式,而且是一種很常用的樂觀鎖實現方式。

所謂多版本,就是一行記錄在資料庫中儲存了多個版本,每個版本以事務ID作為版本號。InnoDB 裡面每個事務有一個唯一的事務 ID,是在事務開始的時候向InnoDB的事務系統申請的,並且按照申請順序嚴格遞增的。假如一行記錄被多個事務更新,那麼,就會產生多個版本的記錄。

以某一行資料作為例子:

 

經過兩次事務的操作,value從22變成了19,同時,保留了三個事務id,15、25、30。

在每個記錄多版本的基礎上,需要利用“一致性檢視”,來做版本的可見性判斷。

這裡,我們要區分MySQL裡面的兩個”檢視”概念:

  • 一個是view,通過語法create view … 實現,主要建立一個虛擬表,用來執行查詢語句。
  • 一個是InnoDB用來實現mvcc的一致性檢視(consistent read view),純邏輯概念,沒有物理結構,定義了在事務期間,你能看到哪些版本的資料。

我們全文提到的“檢視”都是第二種,主要是支援InnoDB在“讀已提交”和“可重複讀”級別的併發訪問問題。

  • “讀未提及”級別下,沒有一致性檢視
  • “讀已提交”級別下,會在 每個SQL開始執行的時候 建立一致性檢視
  • “可重複讀”級別下,會在 每個事務開始的時候 建立一致性檢視
  • “序列化”級別下,直接通過加鎖避免併發問題

下面,我們簡單介紹一下建立一致性檢視的邏輯。

以“可重複讀”級別為例。

  • 當一個事務開啟的時候,會向系統申請一個新事務id
  • 此時,可能還有多個正在進行的其他事務沒有提交,因此在瞬時時刻,是有多個活躍的未提交事務id
  • 將這些未提交的事務id組成一個數組,數組裡面最小的事務id記錄為低水位,當前系統建立過的事務id的最大值+1記錄為高水位
  • 這個陣列array 和 高水位,就組成了“一致性檢視”。

有了一致性檢視後,我們就可以判斷一行資料的多版本可見性了,無論是“讀已提交”還是“可重複讀”級別,可見性判斷規則是一樣的,區別在於建立快照(一致性檢視)的時間。

在當前事務中,讀取其他某一行的記錄,對其中的版本號的可見性判斷有五種情況(建議自己跟著捋一捋,挺重要的):

  • 如果版本號小於“低水位”,說明事務已經提交,那肯定 可見;
  • 如果版本號大於“高水位”,說明這行資料的這個事務id版本是在快照後產生的,那肯定 不可見;
  • 如果版本號在事務陣列array中,說明這個事務還沒提交,所以 不可見;
  • 如果版本號不在事務陣列array中,且低於高水位,說明這個事務已經提交,所以 可見;
  • 當然,無論什麼時候,自己的事務id中的任何變化,都是可見的

可以看看下面這個例子,更容易理解。

系統建立過的事務id:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15

事務A啟動,拍個快照

此時未提交的事務id有:7,8,9

一致性檢視:陣列array[7,8,9] + 高水位16(15+1)

對於任意一行資料的可見性判斷如下:

1)小於7的,可見

2)大於16的,說明是快照後產生的,不可見

3)10-15,不在陣列array中,說明已經提交了,可見

4)7,8,9在array中,說明未提交,不可見

兩個重要結論:

  • InnoDB 利用了“所有資料都有多個版本”的這個特性,實現了“秒級建立快照”的能力。
  • MVCC的實現,就是根據當前事務的事務id為依據建立“一致性檢視”,利用一致性檢視來判斷資料版本的可見性。

3.隔離性實戰

下面,我們來兩個實戰案例,將上面的基礎概念與實現融會貫通吧。

1)併發select&update 案例

id=1 的value初始為1。

 

我們看下,在不同隔離級別,Time5、Time7、Time9事務A查詢到的value 分佈為多少。

  • “讀未提交”:2,2,2
  • “讀以提交”:1,2,2
  • “可重複讀”:1,1,2
  • 序列化:1,1,2(注意,這裡在事務A提交前,事務B都會阻塞,直到事務A提交後才能執行)

2)併發update案例

id=1 的value初始為1,在可重複讀級別:

 

我們看一下,你猜猜事務A和事務B讀取的value是多少?

答案是:1 和 3

可能會產生困惑,事務A在啟動後快照,所以讀到了1是正常的,但是事務2在啟動的時候快照了,然後在自己的事務中+1,怎麼會讀到3而不是2呢?

原因很簡單,即使是在可重複讀的級別,事務 更新資料 的時候,只能用當前讀(想想也能理解,不然update就出現資料不一致了)。

如果當前的記錄的行鎖被其他事務佔用的話,就需要進入鎖等待。而讀提交的邏輯和可重複讀的邏輯類似,它們最主要的區別是:在可重複讀隔離級別下,只需要在事務開始的時候建立一致性檢視,之後事務裡的其他查詢都共用這個一致性檢視;在讀提交隔離級別下,每一個語句執行前都會重新算出一個新的檢視。

這裡,我們需要注意的是事務的啟動時機。

  • begin/start transaction 命令並不是一個事務的起點,在執行到它們之後的第一個操作 InnoDB 表的語句,事務才真正啟動,一致性檢視是在執行第一個快照讀語句時建立的。
  • 如果你想要馬上啟動一個事務,可以使用 start transaction with consistent snapshot 這個命令,一致性檢視是在執行 start transaction with consistent snapshot 時建立的。

4.關於幻讀

首先明確一下,什麼是幻讀?開篇介紹了什麼是幻讀,這裡再申明一下幻讀出現的場景

  • 第一:事務的隔離級別為可重複讀,且是當前讀
  • 第二:幻讀僅專指新插入的行,在範圍查詢中,後一次查詢出現了新的資料行。

前文已經提到了,對於普通資料庫,需要到可序列化的隔離級別才能解決幻讀問題。

而對於InnoDB儲存引擎來說,在可重複讀級別下就能解決幻讀問題。

InnoDB儲存引擎有三種行鎖演算法:

  • 行鎖:當個行記錄上的鎖
  • 間隙鎖:Gap Lock,鎖定一個範圍,但不包含記錄本身
  • Next-Key Lock:就是行鎖+間隙鎖,同時鎖上一個範圍,並且鎖定記錄本身

InnoDB就是通過Next-Key Lock解決了幻讀的問題,具體內容可以看我之前的文章: 前阿里資料庫專家總結的MySQL裡的各種鎖(下篇)

 

看到這裡了,原創不易,點個關注、點個贊吧,你最好看了~

知識碎片重新梳理,構建Java知識圖譜:https://github.com/saigu/JavaKnowledgeGraph(歷史文章查閱非常方便)

掃碼關注我的公眾號“阿丸筆記”,第一時間獲取最新更新。同時可以免費獲取海量Java技術棧電子書、各個大廠面試題。

相關推薦

面試小時MySQL事務隔離基本概念深入實現

提到MySQL的事務,我相信對MySQL有了解的同學都能聊上幾句,無論是面試求職,還是日常開發,MySQL的事務都跟我們息息相關。 而事務的ACID(即原子性Atomicity、一致性Consistency、隔離性Isolation、永續性Durability)可以說涵蓋了事務的全部知識點,所以,我們不僅要知

面試小時MySQL事務說完原子、一致性、永續性的實現

提到MySQL的事務,我相信對MySQL有了解的同學都能聊上幾句,無論是面試求職,還是日常開發,MySQL的事務都跟我們息息相關。 而事務的ACID(即原子性Atomicity、一致性Consistency、隔離性Isolation、永續性Durability)可以說涵蓋了事務的全部知識點,所以,我們不僅要知

騰訊面試居然我扯了小時的CountDownLatch

一個長頭髮、穿著清爽的小姐姐,拿著一個嶄新的Mac筆記本向我走來,看著來勢洶洶,我心想著肯定是技術大佬吧!但是我也是一個才華橫溢的人,穩住我們能贏。 ![面試官](https://img-blog.csdnimg.cn/20200509090547451.jpeg#pic_center) > **面試官**

頭條面試居然我扯了小時的Semaphore

一個長頭髮、穿著清爽的小姐姐,拿著一個嶄新的Mac筆記本向我走來,看著來勢洶洶,我心想著肯定是技術大佬吧!但是我也是一個才華橫溢的人,穩住我們能贏。 ![](https://img-blog.csdnimg.cn/20200607091134202.png#pic_center) > **面試官**:看你

一個HashMap能面試扯上半個小時

### 一個HashMap能跟面試官扯上半個小時 > 《安琪拉與面試官二三事》系列文章 > [一個HashMap能跟面試官扯上半個小時](https://blog.csdn.net/zhengwangzw/article/details/104889549) > [一個synchroniz

## 【分散式事務面試問我:MySQL中的XA事務崩潰瞭如何恢復??

## 寫在前面 > 前段時間搭建了一套MySQL分散式資料庫叢集,資料庫節點有12個,用來測試各種分散式事務方案的效能和優缺點。測試MySQL XA事務時,正當測試指令碼向資料庫中批量插入資料時,強制伺服器斷電!注意:是直接拔電源,使其瞬間斷電,再次重啟伺服器後,MySQL資料庫報錯了。特此記錄MyS

面試講Binder(二)之關於AIDL的認識

面試官開口說:“聽你剛才所說,在Android系統中,都是利用Binder來進行程序間通訊的,那我怎麼聽說,還有利用AIDL來實現程序間通訊的呢?”。 其實,AIDL只是一種描述性語言,其全稱是Android Interface Definition Language,即介

面試問“為什麼選擇mysql資料庫”說開去

前幾天面試,面試官問我:“為什麼選擇mysql資料庫”。現在想想,有如下的問題需要解決 關係型資料庫有什麼特點及舉例 非關係型資料庫有什麼特點及舉例 關係型資料庫與非關係型資料庫有什麼區別 關係型資

看完這篇HTTP面試扯皮就沒問題了

我是一名程式設計師,我的主要程式語言是 Java,我更是一名 Web 開發人員,所以我必須要了解 HTTP,所以本篇文章就來帶你從 HTTP 入門到進階,看完讓你有一種恍然大悟、醍醐灌頂的感覺。 最初在有網路之前,我們的電腦都是單機的,單機系統是孤立的,我還記得 05 年前那會兒家裡有個電腦,想打電腦遊戲還得

【原創】面試:談談你對mysql聯合索引的認識?

引言 本文預計分為兩個部分: (1)聯合索引部分的基礎知識 在這個部分,我們溫習一下聯合索引的基礎 (2)聯合索引部分的實戰題 在這個部分,列舉幾個我認為算是實戰中的代表題,挑出來說說。 正文 基礎 講聯合索引,一定要扯最左匹配!放心,我不扯有的沒的,幾句話懂個大概就行! 最左匹配 所謂最左原則指的就是如果你

這個案例寫出來還怕面試扯不明白 OAuth2 登入流程?

昨天和小夥伴們介紹了 OAuth2 的基本概念,在講解 Spring Cloud Security OAuth2 之前,我還是先來通過實際程式碼來和小夥伴們把 OAuth2 中的各個授權模式走一遍,今天我們來看最常用也最複雜的授權碼模式。 本文我將通過一個完整的 Demo ,注意,是一個完整的 Demo,帶領

面試:你知道哪些事務失效的場景?

前言 宣告式事務是Spring功能中最爽之一,可是有些時候,我們在使用宣告式事務並未生效,這是為什麼呢? 文章首發於微信公眾號【碼猿技術專欄】 今天陳某帶大家來聊一聊宣告事務的幾種失效場景。本文將會從以下兩個方面來說一下事務為什麼會失效? @Transactional介紹 @Transactional失效場

面試突然問我MySQL儲存過程我竟然連基礎都不會!(詳細)

**所有知識體系文章,[GitHub](https://github.com/Ziphtracks/JavaLearningmanual)已收錄,歡迎Star!再次感謝,願你早日進入大廠!** **GitHub地址:** [https://github.com/Ziphtracks/JavaLearning

看完這篇 HashSet面試扯皮沒問題了

> 我是風箏,公眾號「古時的風箏」,一個兼具深度與廣度的程式設計師鼓勵師,一個本打算寫詩卻寫起了程式碼的田園碼農! 文章會收錄在 [JavaNewBee](https://github.com/huzhicheng/JavaNewBee) 中,更有 Java 後端知識圖譜,從小白到大牛要走的路都在裡面。 之

面試中的老大難-mysql事務和鎖一次性講清楚!

眾所周知,`事務和鎖`是mysql中非常重要功能,同時也是面試的重點和難點。本文會詳細介紹`事務和鎖`的相關概念及其實現原理,相信大家看完之後,一定會對`事務和鎖`有更加深入的理解。 > 本文主要內容是根據掘金小冊《從根兒上理解 MySQL》整理而來。如想詳細瞭解,建議購買掘金小冊閱讀。 ##

MySQL面試問我:MySQL如何實現無資料插入有資料更新?我是這樣回答的!

## 寫在前面 > 馬上就是金九銀十的跳槽黃金期了,很多讀者都開始出去面試了。這不,又一名讀者出去面試被面試官問了一個MySQL的問題:向MySQL中插入資料,如何實現MySQL中沒有當前id標識的資料時插入資料,有當前id標識的資料時更新資料。其實,這題目一點也不難!! ## 先來個簡單題目 正

mysql事務隔離級別與鎖的關系

美團 enc 自己 ren 問題總結 關系 sql 事務 sql事務 其實操作了這麽久mysql一直也沒有把mysql中事務跟鎖的關系弄得特別清楚。然後搜到美團這篇文章,順便結合一下自己遇到的問題總結一下。 首先事務有四種隔離級別: Refere

mysql事務隔離級別

也有 超時 改變 提交 已提交 style pda 結果 多個實例 概念 隔離級別用於決定如果控制並發用戶如何讀寫數據的操作,同時對性能也有一定的影響作用。 臟讀:讀取未提交的數據; 不可重復讀(Non-repeatable read):在一個事務的兩次查詢之中

MySQL事務隔離級別詳解

默認 多少 bcf 結構 有一個 個數 ref tle eat 轉載自: MySQL事務隔離級別詳解 SQL標準定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低級別的隔離級一般支持更高的並發處理,並擁有更低的系統開銷。Read

事務隔離級別和mysql事務隔離級別修改

eat log control 容易 新的 pda mit 全局 nbsp A事務做了操作 沒有提交 對B事務來說 就等於沒做 獲取的都是之前的數據 但是 在A事務中查詢的話 查到的都是操作之後的數據 沒有提交的數據只有自己看得到,並沒有update到數據庫。 查看In