MySQL - 當前讀和快照讀


當前讀和快照讀

InnoDB 給每一個事務生成一個唯一事務 ID 的方法稱為生成快照,因此這種場景稱為快照讀

但是對於更新數據不能使用快照讀,因為更新數據時如果使用快照讀會可能會覆蓋其他事務的更改。

另外查詢時如果加鎖也會采用當前讀的方式。當前讀就是讀這個數據最新的提交數據。

InnoDB 的多版本並發控制實現了在串行化的隔離級別下讀不加鎖,提高了並發性能。

當前讀

當前讀的場景有下面幾種:

update ... (更新操作)

delete ... (刪除操作)

insert ... (插入操作)

select ... lock in share mode (共享讀鎖)

select ... for update (寫鎖)

當前讀,讀取的是最新版本,並且對讀取的記錄加鎖,阻塞其他事務同時修改相同記錄,避免出現安全問題。

例如,假設要update一條記錄,但是另一個事務已經delete這條數據並且commit了,如果不加鎖就會產生沖突。所以update的時候肯定要是當前讀,得到最新的信息並且鎖定相應的記錄。

快照讀

快照讀的場景:

單純的select操作
(不包括上面當前讀的select ... lock in share mode,select ... for update)

Read Committed隔離級別:每次select都生成一個快照讀

Read Repeatable隔離級別:開啟事務后第一個select語句才是快照讀的地方,而不是一開啟事務就快照讀

例子

下面通過一個例子來理解快照讀和當前讀:

首先建一個表 t,並插入一條數據。

mysql-> create table t(k int)ENGINE=InnoDB;
mysql-> insert into t(k) values (1);

然后將事務的隔離級別設置為 REPEATABLE-READ,接着開啟三個事務,並按照下面的順序進行執行。

MySQL 中事務開始的時間

一般我們會認為 begin/start transaction 是事務開始的時間點,也就是一旦我們執行了 start transaction,就認為事務已經開始了,其實這是錯誤的。事務開始的真正的時間點(LSN),是 start transaction 之后執行的第一條語句,不管是什么語句,不管成功與否

但是如果你想要達到將 start transaction 作為事務開始的時間點,那么我們必須使用:

start transaction with consistent snapshot

它的含義是:執行 start transaction 同時建立本事務一致性讀的 snapshot . 而不是等到執行第一條語句時,才開始事務,並且建立一致性讀的 snapshot .

效果等價於: start transaction 之后,馬上執行一條 select 語句(此時會建立一致性讀的snapshot)。

事務A 事務B 事務C 說明
start transaction with consistent snapshot 開啟事務A
start transaction with consistent snapshot 開啟事務B
select k from t; 事務A讀取結果是1(快照讀)
select k from t; 事務B讀取結果是1(快照讀)
update t set k = k + 1; 事務C提交的k為2
update t set k = k + 1; update 語句進行了一次當前讀將 k 的值更新為事務 C 已經提交的結果 2,並且在此基礎上再加1得到3
select k from t; 執行了 update 操作時會創建一個新版本的數據,並且將自己的事務 ID 作為該數據的版本號,因此在該事務內可以讀到自己更新的數據。因此事務 B 最后一次查詢的結果是 3。
commit; 事務B提交
select k from t; 事務A讀取結果是1(快照讀)
commit; 事務A提交
select k from t; 讀取結果是 3

圖示:

當前讀和快照讀

參考
https://juejin.im/post/6844903928627200007
https://www.cnblogs.com/digdeep/p/4947694.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM