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 | 當出現讀寫鎖沖突時候,後通路的事務必須等前一個事務執行完成,才能繼續執行 |
事務的啟動
- 顯示啟動事務:begin 或 start transaction。配套的送出語句是 commit,復原語句是 rollback。
- set autocommit=0,這個指令會将這個線程的自動送出關掉。意味着如果你隻執行一個 select 語句,這個事務就啟動了,而且并不會自動送出。這個事務持續存在直到你主動執行 commit 或 rollback 語句,或者斷開連接配接。
建議你總是使用 set autocommit=1
長事務的風險
- 長事務系統裡面會存在很老的事務視圖。由于這些事務随時可能通路資料庫裡面的任何資料,是以這個事務送出之前,資料庫裡面它可能用到的復原記錄都必須保留,這就會導緻大量占用存儲空間。
- 長事務還占用鎖資源,也可能拖垮整個庫。
tips:
1.盡量不要使用長事務
2.有些用戶端連接配接架構會預設連接配接成功後先執行一個 set autocommit=0 的指令。這就導緻接下來的查詢都在事務中,如果是長連接配接,就導緻了意外的長事務。
查詢是否有長事務
#查找持續時間超過 60s 的事務
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60
下一章:索引模型和B+樹索引