mysql事務ACID原理MVCC 幻讀

mysql事務原理MVCC

書籍推薦:mysql必知必會

​ 深入淺出mysql

​ mysql高性能(偏DBA)

數據量較小:索引(一個庫)

數據量較大:分庫分表,讀寫分離

mysql優化是一個大的範圍,需要豐富的經驗,課程中會把作爲一個java程序員(非DBA)基本的、常用的一一列舉出來,希望大家儘可能多的掌握,因爲太多了,而我們重點在java,所以每個知識點都只會抽取重點來學習。如果以後大家項目中需要這方面的,大家以這個爲基礎,再去深入學習,也是沒有問題的。

select * from xxx where id=1

在這裏插入圖片描述

①建立連接1.1(Connectors&Connection Pool),通過客戶端/服務器通信協議與MySQL建立連
接。MySQL 客戶端與服務端的通信方式是 “ 半雙工 ”。對於每一個 MySQL 的連接,時刻都有一個
線程狀態來標識這個連接正在做什麼。
通訊機制:
全雙工:能同時發送和接收數據,例如平時打電話。
半雙工:指的某一時刻,要麼發送數據,要麼接收數據,不能同時。例如早期對講機
單工:只能發送數據或只能接收數據。例如單行道
線程狀態:系統故障






show processlist; //查看用戶正在運行的線程信息,root用戶能查看所有線程,其他用戶只能看自
己的
id:線程ID,可以使用kill xx;
user:啓動這個線程的用戶
Host:發送請求的客戶端的IP和端口號
db:當前命令在哪個庫執行
Command:該線程正在執行的操作命令
Create DB:正在創建庫操作
Drop DB:正在刪除庫操作
Execute:正在執行一個PreparedStatement
Close Stmt:正在關閉一個PreparedStatement
Query:正在執行一個語句
Sleep:正在等待客戶端發送語句
Quit:正在退出
Shutdown:正在關閉服務器
Time:表示該線程處於當前狀態的時間,單位是秒
State:線程狀態
Updating:正在搜索匹配記錄,進行修改
Sleeping:正在等待客戶端發送新請求
Starting:正在執行請求處理
Checking table:正在檢查數據表
Closing table : 正在將表中數據刷新到磁盤中
Locked:被其他查詢鎖住了記錄
Sending Data:正在處理Select查詢,同時將結果發送給客戶端
Info:一般記錄線程執行的語句,默認顯示前100個字符。想查看完整的使用show full
processlist;
























②查詢緩存(Cache&Buffer),這是MySQL的一個可優化查詢的地方,如果開啓了查詢緩存且在
查詢緩存過程中查詢到完全相同的SQL語句,則將查詢結果直接返回給客戶端;如果沒有開啓查詢
緩存或者沒有查詢到完全相同的 SQL 語句則會由解析器進行語法語義解析,並生成“解析樹”。

緩存Select查詢的結果和SQL語句
執行Select查詢時,先查詢緩存,判斷是否存在可用的記錄集,要求是否完全相同(包括參
數值),這樣纔會匹配緩存數據命中。
即使開啓查詢緩存,以下SQL也不能緩存
查詢語句使用SQL_NO_CACHE
查詢的結果大於query_cache_limit設置
查詢中有一些不確定的參數,比如now()
show variables like '%query_cache%'; //查看查詢緩存是否啓用,空間大小,限制等
show status like 'Qcache%'; //查看更詳細的緩存參數,可用緩存空間,緩存塊,緩存多少等

③解析器(Parser)將客戶端發送的SQL進行語法解析,生成"解析樹"。預處理器根據一些MySQL
規則進一步檢查“解析樹”是否合法,例如這裏將檢查數據表和數據列是否存在,還會解析名字和別
名,看看它們是否有歧義,最後生成新的“解析樹”。

查詢優化器(Optimizer)根據“解析樹”生成最優的執行計劃。MySQL使用很多優化策略生成最
優的執行計劃,可以分爲兩類:靜態優化(編譯時優化)、動態優化(運行時優化)。

等價變換策略
A:5=5 and a>5 改成 a > 5 去除恆成立條件
a < b and a=5 改成b>5 and a=5
基於聯合索引,調整條件位置等
優化count、min、max等函數
InnoDB引擎min函數只需要找索引最左邊
InnoDB引擎max函數只需要找索引最右邊
MyISAM引擎count(*),不需要計算,直接返回
提前終止查詢
使用了limit查詢,獲取limit所需的數據,就不在繼續遍歷後面數據
in的優化
MySQL對in查詢,會先進行排序,再採用二分法查找數據。比如where id in (2,1,3),變
成 in (1,2,3) 

B:join優化:inner join/join 自動優化小表驅動大表,left right沒法優化
select from a join b  10萬個  20萬--40萬
select from b join a  1000個  2000-4000   
a表大,b表小,基於主鍵索引,每條數據查詢的IO次數2-4

⑤查詢執行引擎負責執行 SQL 語句,此時查詢執行引擎會根據 SQL 語句中表的存儲引擎類型,以
及對應的API接口與底層存儲引擎緩存或者物理文件的交互,得到查詢結果並返回給客戶端。若開
啓用查詢緩存,這時會將SQL 語句和結果完整地保存到查詢緩存(Cache&Buffer)中,以後若有
相同的 SQL 語句執行則直接返回結果。
如果開啓了查詢緩存,先將查詢結果做緩存操作
返回結果過多,採用增量模式返回




1存儲引擎

存儲引擎:

MySQL中的數據用各種不同的技術存儲在文件(或者內存)中。這些技術中的每一種技術都使用不同的存儲機制、索引技巧、鎖定水平並且最終提供廣泛的不同的功能和能力。通過選擇不同的技術,你能夠獲得額外的速度或者功能,從而改善你的應用的整體功能。

這些不同的技術以及配套的相關功能在 MySQL中被稱作存儲引擎(也稱作表類型)

因爲在關係數據庫中數據的存儲是以表的形式存儲的,所以存儲引擎也可以稱爲表類型(Table Type,即存儲和操作此表的類型)。

Mysql存儲引擎分類:

MyISAM、InnoDB、MEMORY、MERGE等

CREATE TABLE `brand` (
  `id` int(11) NOT NULL AUTO_INCREMENT
) ENGINE=InnoDB DEFAULT CHARSET=utf8; #指定引擎

默認存儲引擎

SHOW ENGINES

在這裏插入圖片描述

1.InnoDB存儲引擎

InnoDB是事務型數據庫的首選引擎,通過上圖也看到了,InnoDB是目前MYSQL的默認事務型引擎,是目前最重要、使用最廣泛的存儲引擎。支持事務安全表(ACID),支持行鎖定和外鍵。InnoDB主要特性有:

1、InnoDB mysql現在默認支持的引擎,每張表的存儲都按主鍵順序存放,如果沒有顯示在表定義時指定主鍵,InnoDB會爲每一行生成一個6字節的隱藏ROWID,並以此作爲主鍵

2、支持事務安全表(ACID),支持行鎖定和外鍵

場景:由於其支持事務處理,支持外鍵,支持崩潰修復能力和併發控制。如果需要對事務的完整性要求比較高(比如銀行),要求實現併發控制(比如售票),那選擇InnoDB有很大的優勢。因爲支持事務的提交(commit)和回滾(rollback)。

總結:(理解並記住)

1.支持事務、支持外鍵
2.支持行級鎖與表級鎖
3.花費資源去處理事務,效率比不上MyISAM
4.有事務日誌,恢復數據較方便
5.索引爲聚簇索引
	雖然InnoDB不斷優化,效率已經有了很大提升,但是還是比不上MyISAM

2.MyISAM存儲引擎

MyISAM基於ISAM存儲引擎,並對其進行擴展。它是在Web、數據倉儲和其他應用環境下最常使用的存儲引擎之一。MyISAM擁有較高的插入、查詢速度,但不支持事物和外鍵。

總結(記住)

Mysql 5.5版本之前的默認的存儲引擎
1.不支持事務、不支持外鍵
2.只支持表級鎖(後面介紹)
3.沒有事務日誌,故障恢復數據較麻煩
4.分區存放文件,平均分配IO,不用花費資源去處理事務,效率較高
5.索引爲非聚簇索引

2.undo和redo的功能

id 1 name 張三

update xxx set name=‘李四’ where id=1

mysql爲提高效率,每次修改不會直接修改磁盤,會先修改buffer,然後再由mysql自己的線程purge去刷新到磁盤。爲了支持回滾,得記錄修改之前得狀態

事務開啓前,先寫undo日誌

undo:

保證了事務原子性

數據修改前的內容(用於回滾),當把數據從磁盤讀取內存的時候,每次數據操作這些數據都會變髒,就是髒數據,需要都會記錄undo日誌。當發生回滾的時候,就需要這些日誌用來回滾數據

Undo:意爲撤銷或取消,以撤銷操作爲目的,返回指定某個狀態的操作。
Undo Log:數據庫事務開始之前,會將要修改的記錄存放到 Undo 日誌裏,當事務回滾時或者數
據庫崩潰時,可以利用 Undo 日誌,撤銷未提交事務對數據庫產生的影響。
Undo Log產生和銷燬:Undo Log在事務開始前產生;事務在提交時,並不會立刻刪除undo
log,innodb會將該事務對應的undo log放入到刪除列表中,後面會通過後臺線程purge thread進
行回收處理。Undo Log屬於邏輯日誌,記錄一個變化過程。例如執行一個delete,undolog會記
錄一個insert;執行一個update,undolog會記錄一個相反的update。
Undo Log存儲:undo log採用段的方式管理和記錄。在innodb數據文件中包含一種rollback
segment回滾段,內部包含1024個undo log segment。可以通過下面一組參數來控制Undo log存
儲。

實現事務的原子性
Undo Log 是爲了實現事務的原子性而出現的產物。事務處理過程中,如果出現了錯誤或者用戶執
行了 ROLLBACK 語句,MySQL 可以利用 Undo Log 中的備份將數據恢復到事務開始之前的狀態。
實現多版本併發控制(MVCC)
Undo Log 在 MySQL InnoDB 存儲引擎中用來實現多版本併發控制。事務未提交之前,Undo Log
保存了未提交之前的版本數據,Undo Log 中的數據可作爲數據舊版本快照供其他併發事務進行快
照讀
 事務A手動開啓事務,執行更新操作,首先會把更新命中的數據備份到 Undo Buffer 中。
 事務B手動開啓事務,執行查詢操作,會讀取 Undo 日誌數據返回,進行快照讀

undo log是用來回滾數據的用於保障 未提交事務的原子性

redo:

數據修改後的內容,在緩衝池,然後數據修改後生成redo日誌,需要把這些內存中的數據插入到磁盤。這個時候當數據庫宕機的時候。這些redo就是重要的記錄,重啓之後會把redo日誌也就是修改的數據重新寫入數據庫。

寫buffer得時候,也會同時寫redo日誌,因爲寫redo(順序io)日誌的速度遠遠高於,寫mysql數據(mysql數據以頁爲單位存儲,隨機io)

保證了ACID的持久性

(1)redo log 的存儲是順序存儲,而緩存同步是隨機操作。

(2)緩存同步是以數據頁爲單位的,每次傳輸的數據大小大於redo log。Redo:顧名思義就是重做。以恢復操作爲目的,在數據庫發生意外時重現操作。
Redo Log:指事務中修改的任何數據,將最新的數據備份存儲的位置(Redo Log),被稱爲重做
日誌。
Redo Log 的生成和釋放:隨着事務操作的執行,就會生成Redo Log,在事務提交時會將產生
Redo Log寫入Log Buffer,並不是隨着事務的提交就立刻寫入磁盤文件。等事務操作的髒頁寫入
到磁盤之後,Redo Log 的使命也就完成了,Redo Log佔用的空間就可以重用(被覆蓋寫入)。
Redo Log工作原理
Redo Log 是爲了實現事務的持久性而出現的產物。防止在發生故障的時間點,尚有髒頁未寫入表
的 IBD 文件中,在重啓 MySQL 服務的時候,根據 Redo Log 進行重做,從而達到事務的未入磁盤
數據進行持久化這一特性

redo log是用來恢復數據的 用於保障,已提交事務的持久化特性
(1)redo log 的存儲是順序存儲,而緩存同步是隨機操作。

(2)緩存同步是以數據頁爲單位的,每次傳輸的數據大小大於redo log。
假設有A、B兩個數據,值分別爲1,2.
1. 事務開始
2. 記錄A=1到undo log
3. 修改A=3
4. 記錄A=3到 redo log
5. 記錄B=2到 undo log
6. 修改B=4
7. 記錄B=4到redo log
8. 將redo log寫入磁盤
9. 事務提交

3.mysql鎖

1.增刪改,mysql會默認加寫鎖

2.select * from sing where s_num=‘10001’ lock in share mode;加讀鎖 讀讀可以共享

3.讀寫鎖不共享

4.for update 加的寫鎖

共享鎖與排他鎖

  • 共享鎖(讀鎖):其他事務可以讀,但不能寫。

  • 排他鎖(寫鎖) :其他事務不能讀取,也不能寫。

    MySQL 不同的存儲引擎支持不同的鎖機制,所有的存儲引擎都以自己的方式顯現了鎖機制,服務器層完全不瞭解存儲引擎中的鎖實現:
    
    MyISAM 和 MEMORY 存儲引擎採用的是表級鎖(table-level locking)
    BDB 存儲引擎採用的是頁面鎖(page-level locking),但也支持表級鎖
    InnoDB 存儲引擎既支持行級鎖(row-level locking),也支持表級鎖,但默認情況下是採用行級鎖。
    默認情況下,表鎖和行鎖都是自動獲得的, 不需要額外的命令。
    
    但是在有的情況下, 用戶需要明確地進行鎖表或者進行事務的控制, 以便確保整個事務的完整性,這樣就需要使用事務控制和鎖定語句來完成。
    

    3.1表級鎖

    鎖住整張表,開銷小,加鎖快;不會出現死鎖(因爲MyISAM會一次性獲得SQL所需的全部鎖);鎖定粒度大,發生鎖衝突的概率最高,併發度最低。 演示:兩個cmd

    lock table xxxx write/read

    unlock tables

在這裏插入圖片描述

3.2行級鎖

開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高

select xxx for update

在這裏插入圖片描述

3.3全局鎖

全局鎖就是對整個數據庫實例加鎖。MySQL提供了一個加全局讀鎖的方法,命令是Flush tables with read lock。當需要讓整個庫處於只讀狀態的時候,可以使用這個命令,之後其他線程的以下語句會被阻塞:數據更新語句(數據的增刪改)、數據定義語句(包括建表、修改表結構等)和更新類事務的提交語句

全局鎖的典型使用場景是,做全庫邏輯備份。也就是把整庫每個表都select出來存成文本

但是讓整個庫都只讀,可能出現以下問題:

  • 如果在主庫上備份,那麼在備份期間都不能執行更新,業務基本上就得停擺
  • 如果在從庫上備份,那麼在備份期間從庫不能執行主庫同步過來的binlog,會導致主從延遲

3.4避免阻塞與死鎖

阻塞:食堂排隊

1.詳細的分析產品需求 會有哪些查詢,哪些修改,好好建表,減少長事務操作

2.分佈式事務中,採用弱一致性,可以減少阻塞

3.最直接最簡單的方法就是把表的數據量變小(針對於數據量確實很大了,分庫分表)

4.當然sql語句調優、提高代碼質量等都是很重要的

如果真的出現了:

show full PROCESSLIST:查看狀態,可以參考前面的屬性,必要情況下 直接kill

3.5.mysql死鎖

相互等待對方釋放鎖,形成死鎖

不同表

在這裏插入圖片描述

同一個表

在這裏插入圖片描述

避免死鎖

1.編號解死鎖:對鎖編號,按順序鎖。 比如AB 每個線程都做判斷,始終先鎖A 在鎖B

2.首先在innodb搜索引擎中,會根據算法主動進行部分死鎖的檢測與釋放,比如上面的例子自動釋放。

3.大事務拆小。大事務更傾向於死鎖,大事務鎖的時間長,如果業務允許,將大事務拆小(DBA建表功底)。

4.爲表添加合理的索引

4.MVCC多版本併發控制

最主要就是解決讀寫互斥,寫時複製讀寫分離,空間換時間

id :1 name 張三

事務1:select * from xxx where id=1 ------>複製在一個地方

事務2:update xxx where id=1 數據庫改

改的地方跟我讀的不是同一個,讀寫分離

MVCC
MVCC,全稱Multi-Version Concurrency Control,即多版本併發控制。MVCC是一種併發控制的方法,一般在數據庫管理系統中,實現對數據庫的併發訪問,在編程語言中實現事務內存。什麼是當前讀和快照讀?

在學習MVCC多版本併發控制之前,我們必須先了解一下,什麼是MySQL InnoDB下的當前讀和快照讀?

  • 當前讀
    像select lock in share mode(共享鎖), select for update ; update, insert ,delete(排他鎖)這些操作都是一種當前讀,爲什麼叫當前讀?就是它讀取的是記錄的最新版本,讀取時還要保證其他併發事務不能修改當前記錄,會對讀取的記錄進行加鎖。

    A事務:select * from xxxx in share mode 當前讀,讀取到數據庫最新數據

    ​ 一系列操作…

    ​ select * from xxxx in share mode 當前讀,讀取到數據庫最新數據

    ​ 因爲加鎖,如果沒有鎖,使用當前讀,就會出現不可重複讀,幻讀

  • 快照讀
    像不加鎖的select操作就是快照讀,即不加鎖的非阻塞讀;快照讀的前提是隔離級別不是串行級別,串行級別下的快照讀會退化成當前讀;之所以出現快照讀的情況,是基於提高併發性能的考慮,快照讀的實現是基於多版本併發控制,即MVCC,可以認爲MVCC是行鎖的一個變種,但它在很多情況下,避免了加鎖操作,降低了開銷;既然是基於多版本,即快照讀可能讀到的並不一定是數據的最新版本,而有可能是之前的歷史版本

    A事務:select * from xxxx 把當前這個時刻的記錄照個相,在內存中就是複製了一份數據

    ​ 一系列操作。。。。操作的過程中有可能其它事務已經更改了數據

    ​ select * from xxxx 這次讀取不會讀到其它事務修改數據,因爲在一個事務中如果沒有觸發當前讀,那 麼就只會有一次快照讀

    ​ 所以mvcc的快照讀就在不加鎖的鎖 的情況下解決了不可重複讀,既然沒有加鎖,那麼這邊查詢,其它事務就可以更改,於是解決讀寫衝突

數據庫併發場景有三種,分別爲:(針對沒有措施的情況下)

  • 讀-讀:不存在任何問題,也不需要併發控制

  • 讀-寫:有線程安全問題,可能會造成事務隔離性問題,可能遇到髒讀,幻讀,不可重複讀

  • 寫-寫:有線程安全問題,可能會存在更新丟失問題,比如第一類更新丟失,第二類更新丟失

第一類更新丟失:

A事務撤銷了B事務操作
在這裏插入圖片描述

第二類更新丟失

A事務覆蓋B事務已經提交的數據,造成B事務所做操作丟失

在這裏插入圖片描述

mvcc如何解決隔離性

隱式字段

每行記錄除了我們自定義的字段外,還有數據庫隱式定義的DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等字段

id: 1 name zhangsan 事務id:1

  • DB_TRX_ID
    6byte,最近修改(修改/插入)事務ID:記錄創建這條記錄/最後一次修改該記錄的事務ID

  • DB_ROLL_PTR
    7byte,回滾指針,指向這條記錄的上一個版本(存儲於rollback segment裏)undo日誌記錄了很多操作

    當前的這條數據,得找到對應得日誌,靠指針

  • DB_ROW_ID
    6byte,隱含的自增ID(隱藏主鍵),如果數據表沒有主鍵,InnoDB會自動以DB_ROW_ID產生一個聚簇索引

  • 實際還有一個刪除flag隱藏字段, 既記錄被更新或刪除並不代表真的刪除,而是刪除flag變了

在這裏插入圖片描述

undo日誌只是記錄得事務操作得反向操作.

A事務正在執行,把buffer age改成25,但是沒有提交

B事務來讀取數據,應該讀取24,24哪兒來呢

Read View

什麼是Read View,說白了Read View就是事務進行快照讀操作的時候生產的讀視圖

在這裏插入圖片描述

當每個事務開啓時,都會被分配一個ID, 這個ID是遞增的,所以最新的事務,ID值越大

Read View簡單的理解成有三個全局屬性:

trx_list
一個數值列表,用來維護Read View生成時刻系統正活躍的事務ID  
例如:
我自己的事務時事務2
1操作未提交 3操作未提交 4已經提交  放入trx_list:[1,3]
low_limit_id
記錄trx_list列表中事務ID最小的ID   就是1
next_limit_id
ReadView生成時刻系統尚未分配的下一個事務ID,也就是目前已出現過的事務ID的最大值+1
5

1.如果當前buffer裏面的事務id x小於trx_list裏面的最小id(low_limit_id) 可以讀取這個事務id x的數據
事務2開啓,事務3開啓,我是事務4,事務5 ,  事務id是自增的 buffer的順序應該1-2-3-4-5,那個事務最近操作了我,事務id就是誰
事務4開啓事務,生成快照讀,讀取到buffer中當前字段的隱藏事務id是1. 因爲事務1的操作一定在2345前面,所以事務id能爲1一定是事務1回滾或者提交了
第一條滿足就不會走後面
2.如果第一條沒有滿足,比較讀取到buffer中的事務id,比next_limit_id還大,不可讀取,我生成快照的時候最大值就是5,你比5還大說明生成快照的時候壓根沒有開啓這個事務,肯定不能讀取。
3.2條滿足的情況下,把在buffer中讀取到的事務id,去trx_list裏面遍歷,如果trx_list裏面有說明還在活躍,不能讀取,否則可以讀取

因爲這三條,使用mvcc 樂觀鎖來保證併發隔離性,並沒有加鎖

在這裏插入圖片描述

讀已提交RC read-commited

會出現不可重複讀

A事務: 第一次select 生成快照

​ 第二次select 又會生成快照

​ 每一次都會生成快照

會不會髒讀?不會,因爲上面的mvcc條件判斷

會不會不可重複讀呢?會出現, 比如上面的例子,第一次4提交,3沒有提交。buffer中的事務id是4 根據條件4滿足直接讀取。如果第二次快照3提交了,buffer中事務id是3,根據地址。直接定位3的版本鏈.兩次的結果不一致

readview會改變

解決不可重複讀RR read-repeatable

只是多次讀取,只會有一次快照

A事務: 第一次select 生成快照

​ 第二次select 不會生成

肯定避免了不可重複讀

A事務第一次讀取了,另外一個事務修改了,A事務再次讀取數據一致

解決不了幻讀

如果只是多次讀取是可以解決幻讀的,因爲不會出現當前讀,只會生成一次快照。

1.a事務先select(觸發快照生成),b事務insert確實會加一個gap鎖,但是如果b事務commit,這個gap鎖就會釋放(釋放後a事務可以隨意操作), student表9條數據,生成快照,b事務插入/刪除了一條數據,並且提交

2.a事務再select出來的結果在MVCC下還和第一次select一樣,不會幻讀,生成了一次快照了不會再次生成,沒有幻讀

3.接着a事務不加條件地update,這個update會作用在所有行上(包括b事務新加的),

​ update 需要更新全表

​ 增刪改觸發鎖,觸發當前讀,需要讀取最新的數據,讀取到10條

4.a事務再次select就會出現b事務中的新行,並且這個新行已經被update修改了. 剛纔的快照讀已經丟失了,因爲在中間有一次當前讀

上面這樣,事務2提交之後,事務1再次執行update,因爲這個是當前讀,他會讀取最新的數據,包括別的事務已經提交的,所以就會導致此時前後讀取的數據不一致,出現幻讀。

在這裏插入圖片描述

InnoDB有三種行鎖的算法:

儘量彌補錯誤。

1,Record Lock:單個行記錄上的鎖。

2,Gap Lock:間隙鎖,鎖定一個範圍,但不包括記錄本身。GAP鎖的目的,是爲了防止同一事務的兩次當前讀,出現幻讀的情況。

3,Next-Key Lock:1+2,鎖定一個範圍,並且鎖定記錄本身。對於行的查詢,都是採用該方法,主要目的是解決幻讀的問題

在這裏插入圖片描述

超時時間的參數:innodb_lock_wait_timeout ,默認是50秒。
超時是否回滾參數:innodb_rollback_on_timeout 默認是OFF。

默認情況下,InnoDB存儲引擎不會回滾超時引發的異常,除死鎖外。

因爲InnoDB對於行的查詢都是採用了Next-Key Lock的算法,鎖定的不是單個值,而是一個範圍,按照這個方法是會和第一次測試結果一樣。但是,當查詢的索引含有唯一屬性的時候,Next-Key Lock 會進行優化,將其降級爲Record Lock,即僅鎖住索引本身,不是範圍。

注意:通過主鍵或則唯一索引來鎖定不存在的值,也會產生GAP鎖定

如何讓測試一不阻塞?可以顯式的關閉Gap Lock:

1:把事務隔離級別改成:Read Committed,提交讀、不可重複讀。SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

2:修改參數:innodb_locks_unsafe_for_binlog 設置爲1。

mvcc+間隙鎖:完成了事務隔離性但是依然沒有徹底解決幻讀吧

5.總結

對ACID的回答要提高,幻讀,不可重複讀

undo日誌:保證原子性

redo日誌:保證持久性

mvcc+鎖:保證隔離性

原子性+持久性+隔離性=一致性(最終目的)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章