天天看點

mysql-3.事務特性和隔離級别

tips:mysql中的事務實在引擎層實作的,mysql是以插件的方式支援多種引擎。但并不是所有引擎都支援事務。InnoDB支援事務,但是MyISAM就不支援。這也是為什麼MyISAM會逐漸被InnoDB取代的原因。

下面所有講的事務相關的都是以InnoDB為例介紹的

事務特性

提到事務我們最先想到的都是事務的幾個特性ACID:

  • 原子性:同一個事務裡的操作是一個整體,要麼都成功,要麼都失敗
  • 一緻性:事務前後資料的完整性必須保持一緻
  • 隔離性:事務的隔離性是多個使用者并發通路資料庫時,資料庫為每一個使用者開啟的事務,不能被其他事務的操作資料所幹擾,多個并發事務之間要互相隔離。
  • 持久性:持久性是指一個事務一旦被送出,它對資料庫中資料的改變就是永久性的,接下來即使資料庫發生故障也不應該對其有任何影響

隔離性與隔離級别

當資料庫上有多個事務同時執行的時候,就可能出現髒讀(dirty read)、不可重複讀(non-repeatable read)、幻讀(phantom read)的問題,為了解決這些問題,就有了“隔離級别”的概念。

SQL标準的事務隔離級别:

  • 讀未送出(read uncommitted):一個事務還沒送出,他所作的更改能被别的事務看到
  • 讀已送出(read committed):一個事務送出後,他所作的更改才能被别的事務看到
  • 可重複讀(repeatable read):一個事務執行過程中看到的資料,總跟這個事務啟動時看到的資料一緻。同時,可重複讀級别,未送出的變更也不能被别的事務看到。
  • 串行(serializable):對于同一行記錄,“寫”會加“寫鎖”,“讀”會加“讀鎖”。當出現讀寫鎖沖突的時候,後通路的事務必須等前一個事務執行完成,才能繼續執行。
tips:上述隔離級别從上到下依次提高的,但是你隔離級别越高,約嚴實,效率越低,是以需要找一個平衡點。

檢視資料庫目前隔離級别:

show variables like 'transaction_isolation';

我們可以通過一個例子示範上面的事務隔離級别:

1.建立一張表,插入一條資料

create table T(c int) engine=InnoDB;
insert into T(c) values(1);
           
事務A 事務B
啟動事務A->查詢得到值1 啟動事務B
查詢得到值1
将值1改為2
查詢得到值v1
送出事務B
查詢得到值v2
送出事務A
查詢得到值v3

我們可以通過設定不同的事務級别,看下事務 A 會有哪些不同的傳回結果,也就是圖裡面 V1、V2、V3 的傳回值分别是什麼。

隔離級别 V1 V2 V3值 原因
讀未送出 v1=2;v2=2;v3=2 事務A可以讀到事務B未送出的修改
讀已送出 v1=1;v2=2;v3=2 事務A不能讀到事務B未送出的修改
可重複讀 v1=1;v2=1;v3=2 事務A執行過程中看到的資料,總跟它啟動時候一樣。并且可重複讀也不能讀到未送出的變更
串行化 v1=1;v2=1;v3=2 當出現讀寫鎖沖突時候,後通路的事務必須等前一個事務執行完成,才能繼續執行

事務的啟動

  1. 顯示啟動事務:begin 或 start transaction。配套的送出語句是 commit,復原語句是 rollback。
  2. set autocommit=0,這個指令會将這個線程的自動送出關掉。意味着如果你隻執行一個 select 語句,這個事務就啟動了,而且并不會自動送出。這個事務持續存在直到你主動執行 commit 或 rollback 語句,或者斷開連接配接。

    建議你總是使用 set autocommit=1

長事務的風險

  1. 長事務系統裡面會存在很老的事務視圖。由于這些事務随時可能通路資料庫裡面的任何資料,是以這個事務送出之前,資料庫裡面它可能用到的復原記錄都必須保留,這就會導緻大量占用存儲空間。
  2. 長事務還占用鎖資源,也可能拖垮整個庫。

tips:

1.盡量不要使用長事務

2.有些用戶端連接配接架構會預設連接配接成功後先執行一個 set autocommit=0 的指令。這就導緻接下來的查詢都在事務中,如果是長連接配接,就導緻了意外的長事務。

查詢是否有長事務

#查找持續時間超過 60s 的事務
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60
           

下一章:索引模型和B+樹索引