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

溫馨提示×

溫馨提示×

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

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

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

發布時間:2020-02-26 00:58:04 來源:網絡 閱讀:277 作者:2578612215 欄目:MySQL數據庫

首先說一下數據庫事務的四大特性

1 ACID

事務的四大特性是ACID(不是"酸"....)

(1) A:原子性(Atomicity)

原子性指的是事務要么完全執行,要么完全不執行.

(2) C:一致性(Consistency)

事務完成時,數據必須處于一致的狀態.若事務執行途中出錯,會回滾到之前的事務沒有執行前的狀態,這樣數據就處于一致的狀態.若事務出錯后沒有回滾,部分修改的內容寫入到了數據庫中,這時數據就是不一致的狀態.

(3) I:隔離性(Isolation)

同時處理多個事務時,一個事務的執行不能被另一個事務所干擾,事務的內部操作與其他并發事務隔離.

(4) D:持久性(Durability)

事務提交后,對數據的修改是永久性的.

2 Mysql的鎖

Mysql的鎖其實可以按很多種形式分類:

  • 按加鎖機制分,可分為樂觀鎖與悲觀鎖.
  • 按兼容性來分,可分為X鎖與S鎖.
  • 按鎖粒度分,可分為表鎖,行鎖,頁鎖.
  • 按鎖模式分,可分為記錄鎖,gap鎖,next-key鎖,意向鎖,插入意向鎖.

這里主要討論S鎖,X鎖,樂觀鎖與悲觀鎖.

(1) S鎖與X鎖

S鎖與X鎖是InnoDB引擎實現的兩種標準行鎖機制.查看默認引擎可使用

show variables like '%storage_engine%';

作者的mysql版本為8.0.17,結果如下:

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

先建好測試庫與測試表,很簡單,表就兩個字段.

create database test;
use test;
create table a
(
id int primary key auto_increment,
money int
);

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

Ⅰ.S鎖

S鎖也叫共享鎖,讀鎖,數據只能被讀取不能被修改.
玩一下,上鎖!

lock table a read;

然后.....

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

只能讀不能改,刪,也不能增.

Ⅱ.X鎖

X鎖也叫排他鎖,寫鎖,一個事務對表加鎖后,其他事務就不能對其進行加鎖與增刪查改操作.

設置手動提交,開啟事務,上X鎖.

set autocmmmit=0;
start transaction;
lock table a write;

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

在開啟另一個事務,使用select語句.

set autocommit=0;
start transaction;
select * from a;

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

這里是阻塞select操作,因為一直都沒釋放X鎖.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

同樣也不能再加鎖,也是阻塞中.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

回到原來那個加鎖的事務,嗯,什么事也沒有,正常讀寫.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

釋放鎖后:

unlock table;

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

在另一個事務中可以看到中斷時間.

(2) 樂觀鎖與悲觀鎖

Ⅰ.樂觀鎖

樂觀鎖就是總是假設是最好的情況,每次去操作的時候都不會上鎖,但在更新時會判斷有沒有其他操作去更新這個數據,是一種寬松的加鎖機制.
mysql本身沒有提供樂觀鎖的支持,需要自己來實現,常用的方法有版本控制和時間戳控制兩種.

  • 版本控制
    版本控制就是為表增加一個version字段,讀取數據時連同這個version字段一起讀出來,之后進行更新操作,版本號加1,再將提交的數據的版本號與數據庫中的版本號進行比較,若提交的數據的版本號大于數據庫中的版本號才會進行更新.

    舉個例子,假設此時version=1,A進行操作,更新數據后version=2,與此同時B也進行操作,更新數據后version=2,A先完成操作,率先將數據庫中的version設置為2,此時B提交,B的version與數據庫中的version一樣,不接受B的提交.

  • 時間戳控制
    時間戳控制與版本控制差不多,把version字段改為timestamp字段
    還有一種實現方法叫CAS算法,這個作者不怎么了解,有興趣可以自行搜索.

Ⅱ.悲觀鎖

悲觀鎖就是總是假設最壞的情況,在整個數據處理狀態中數據處于鎖定狀態,悲觀鎖的實現往往依靠數據庫的鎖機制.每次在拿到數據前都會上鎖.
mysql在調用一些語句時會上悲觀鎖,如(先關閉自動提交,開啟事務):

set autocommit=0;
start transaction;

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

兩個事務都這樣操作,然后其中一個事務輸入:

select * from a where xxx for update;

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

在另一事務也這樣輸入:

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

這時語句會被阻塞,直到上鎖的那個事務commit(解開悲觀鎖).

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

在另一事務中可以看到這個事務被阻塞了2.81s.

*** lock in share mode.

也會加上悲觀鎖.

4 臟讀,幻讀,不可重復讀與兩類丟失更新

(1) 臟讀

臟讀是指一個事務讀取到了另一事務未提交的數據,造成select前后數據不一致.

比如事務A修改了一些數據,但沒有提交,此時事務B卻讀取了,這時事務B就形成了臟讀,一般事務A的后續操作是回滾,事務B讀取到了臨時數值.

事務A 事務B
開始事務 開始事務
更新X,舊值X=1,新值X=2 ?
? 讀取X,X=2(臟讀)
回滾X=1 ?
結束事務(X=1) 結束事務

(2) 幻讀

幻讀是指并不是指同一個事務執行兩次相同的select語句得到的結果不同,而是指select時不存在某記錄,但準備插入時發現此記錄已存在,無法插入,這就產生了幻讀.

事務A 事務B
開始事務 開始事務
select某個數據為空,準備插入一個新數據 ?
? 插入一個新數據
? 提交,結束事務
插入數據,發現插入失敗,由于事務B已插入相同數據 ?
結束事務 ?

(3) 不可重復讀

不可重復讀指一個事務讀取到了另一事務已提交的數據,造成select前后數據不一致.
比如事務A修改了一些數據并且提交了,此時事務B卻讀取了,這時事務B就形成了不可重復讀.

事務A 事務B
開始事務 開始事務
讀取X=1 讀取X=1
更新X=2 ?
提交,結束事務 ?
? 讀取X=2
? 結束事務

(4) 第一類丟失更新

第一類丟失更新就是兩個事務同時更新一個數據,一個事務更新完畢并提交后,另一個事務回滾,造成提交的更新丟失.

事務A 事務B
開始事務 開始事務
讀取X=1 讀取X=1
修改X=2 修改X=3
? 提交,結束事務
回滾 ?
結束事務(X=1) X=1,X本應為提交的3

(5) 第二類丟失更新

第二類丟失更新就是兩個事務同時更新一個數據,先更新的事務提交的數據會被后更新的事務提交的數據覆蓋,即先更新的事務提交的數據丟失.

事務A 事務B
開始事務 開始事務
讀取X=1 讀取X=1
更新X=2 ?
提交事務,X=2,結束 ?
? 更新X=3
? 提交事務,X=3,事務A的更新丟失,結束

5 封鎖協議與隔離級別

封鎖協議就是在用X鎖或S鎖時制定的一些規則,比如鎖的持續時間,鎖的加鎖時間等.不同的封鎖協議對應不同的隔離級別.事務的隔離級別一共有4種,由低到高分別是Read uncommitted,Read committed,Repeatable read,Serializable,分別對應的相應的封鎖協議等級.

(1) 一級封鎖協議

一級封鎖協議對應的是Read uncommitted隔離級別,Read uncommitted,讀未提交,一個事務可以讀取另一個事務未提交的數據,這是最低的級別.一級封鎖協議本質上是在事務修改數據之前加上X鎖,直到事務結束后才釋放,事務結束包括正常結束(commit)與非正常結束(rollback).

一級封鎖協議不會造成更新丟失,但可能引發臟讀,幻讀,不可重復讀.
設置手動提交與事務隔離等級為read uncommited,并開啟事務(注意要先設置事務等級再開啟事務).

set autocommit=0;
set session transaction isolation level read uncommitted;
start transaction;

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

(中間有一行打多了一個t可以忽略.....)

a.引發臟讀

在一個事務中修改表中的值,不提交,另一個事務可以select到未提交的值.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

出現了臟讀.

b.引發幻讀

在一個事務中插入一條數據,提交.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

另一事務中select時沒有,準備insert,但是insert時卻提示已經存在.引發幻讀.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

c.引發不可重復讀

未操作提交前:

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

另一事務修改并提交:

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

再次讀:

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

引發不可重復讀.

(2) 二級封鎖協議

二級封鎖協議本質上在一級協議的基礎上(在修改數據時加X鎖),在讀數據時加上S鎖,讀完后立即釋放S鎖,可以避免臟讀.但有可能出現不可重復讀與幻讀.二級封鎖協議對應的是Read committed與Repeatable Read隔離級別.

先設置隔離等級

set session transaction isolation level read committed;

Ⅰ.Read committed

Read committed,讀提交,讀提交可以避免臟讀,但可能出現幻讀與不可重復讀.

a.避免臟讀

開啟一個事務并更新值,在這個事務中money=100(更新后)

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

另一事務中money為未更新前的值,這就避免了臟讀.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

注意,事實上臟讀在read committed隔離級別下是不被允許的,但是mysql不會阻塞查詢,而是返回未修改之前數據的備份,這種機制叫MVCC機制(多版本并發控制).

b.引發幻讀

在一個事務中插入數據并提交.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

另一事務中不能插入"不存在"的數據,出現幻讀.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

c.引發不可重復讀

事務修改并提交前:

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

事務修改并提交:

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

出現不可重復讀.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

Ⅱ.Repeatable read

Repeatable read比Read committed嚴格一點,是Mysql的默認級別,讀取過程更多地受到MVCC影響,可防止不可重復讀與臟讀,但仍有可能出現幻讀.

a.避免臟讀

在一個事務中修改數據,不提交.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

另一事務中兩次select的結果都不變,沒有出現臟讀.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

b.避免不可重復讀

一個事務修改數據并提交.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

另一事務中select的結果沒有發生改變,即沒有出現不可重復讀.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

c.引發幻讀

同理,一個事務插入一條數據并提交.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

另一個事務插入時出現幻讀.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

(3) 三級封鎖協議

三級封鎖協議,在一級封鎖協議的基礎上(修改時加X鎖),讀數據時加上S鎖(與二級類似),但是直到事務結束后才釋放S鎖,可以避免幻讀,臟讀與不可重復讀.三級封鎖協議對應的隔離級別是Serializable.

先設置Serializable隔離級別

set session transaction isolation level serializable

a.避免臟讀

設置事務隔離等級后開啟事務并update,發現堵塞.從而避免了臟讀.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

b.避免幻讀

插入時直接阻塞,避免了幻讀.

一文帶你理解臟讀,幻讀,不可重復讀與mysql的鎖,事務隔離

c.避免不可重復讀

在臟讀的例子中可以知道,update會被堵塞,都不能提交事務,因此也避免了不可重復讀.

6 兩段鎖協議

事務必須分為兩個階段對數據進行加鎖與解鎖,兩端鎖協議叫2PL(不是2PC),所有的加鎖都在解鎖之前進行.

(1) 加鎖

加鎖會在更新或者

select *** for update
*** lock in share mode

時進行

(2) 解鎖

解鎖在事務結束時進行,事務結束包括rollback與commit.

參考鏈接
1:ACID1

2:ACID2

3:mysql的鎖1

4:樂觀鎖與悲觀鎖1

5:樂觀鎖與悲觀鎖2

6:樂觀鎖與悲觀鎖3

7:mysql修改事務隔離等級

8:mysql三級封鎖與二段鎖

9:數據庫封鎖協議

10:mysql事務隔離機制1

11:mysql事務隔離機制2

12:mysql幻讀

13:mysql臟讀,不可重復讀與幻讀

14:mysql兩段鎖1

15:mysql兩段鎖2

向AI問一下細節

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

AI

嘉禾县| 班玛县| 慈利县| 铜陵市| 林西县| 特克斯县| 丹寨县| 英德市| 济南市| 庆元县| 鞍山市| 宣威市| 清流县| 县级市| 柏乡县| 林州市| 泰来县| 北辰区| 淄博市| 两当县| 定襄县| 天门市| 伊宁县| 太仆寺旗| 成武县| 海口市| 綦江县| 临泽县| 佛教| 玉龙| 石嘴山市| 乐都县| 米林县| 定南县| 邹平县| 巴彦淖尔市| 大兴区| 陆川县| 广灵县| 文山县| 长岭县|