03 事務隔離 事務:保證一組資料庫操作,要麼全部成功,要麼全部失敗。在 MySQL 中,事務支持是在引擎層實現的。 事務ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔離性、持久性)。 建議你儘量不要使用長事務。**** 讀未提交 ...
03 事務隔離
事務:保證一組資料庫操作,要麼全部成功,要麼全部失敗。在 MySQL 中,事務支持是在引擎層實現的。
事務ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔離性、持久性)。
建議你儘量不要使用長事務。****
讀未提交(read uncommitted)、讀提交(read committed)、可重覆讀(repeatable read)和串列化(serializable )
值得註意的是,隔離得越嚴實,效率就會越低。
讀未提交:一個事務還沒提交時,它做的變更就能被別的事務看到。
讀提交:一個事務提交之後,它做的變更才會被其他事務看到。
可重覆讀:一個事務執行過程中看到的數據,總是跟這個事務在啟動時看到的數據是一致的,未提交變更對其他事務也是不可見的。
串列化:對於同一行記錄,“寫”會加“寫鎖”,“讀”會加“讀鎖”。當出現讀寫鎖衝突的時候,後訪問的事務必須等前一個事務執行完成,才能繼續執行。
- 若隔離級別是“讀未提交”, V1 是 2。這時候事務 B 雖然還沒有提交,但是結果已經被 A 看到了。因此,V2、V3 也都是 2。
- 若隔離級別是“讀提交”,V1 是 1,V2 是 2。事務 B 的更新在提交後才能被 A 看到。所以, V3是 2。
- 若隔離級別是“可重覆讀”,則 V1、V2 是 1,V3 是 2。V2 還是 1,事務在執行期間看到的數據前後必須是一致的。
- 若隔離級別是“串列化”, V1、V2 值是 1,V3 的值是 2。事務A一開始查詢值1的時候就獲得了讀鎖,根據兩階段加鎖,事務A獲得的鎖要在commit的時候才釋放,所以事務B在修改1為2的時候申請寫鎖會阻塞直到事務A提交,事務A提交之前獲取的值都是1,所以V1 V2都是1,事務A提交後事務B獲取到寫鎖完成更新操作,所以V3是2。
長事務:意味著系統裡面會存在很老的事務視圖。由於這些事務隨時可能訪問資料庫裡面的任何數據,所以這個事務提交之前,資料庫裡面它可能用到的回滾記錄都必須保留,這就會導致大量占用存儲空間。
MySQL 的事務啟動方式:
- 顯式啟動事務語句:begin 或 start transaction。配套的提交語句是 commit,回滾語句是 rollback。
- set autocommit=0,這個命令會將這個線程的自動提交關掉。意味著如果你只執行一個 select 語句,這個事務就啟動了,而且並不會自動提交。這個事務持續存在直到你主動執行 commit 或 rollback 語句,或者斷開連接。
建議你總是使用 set autocommit=1, 通過顯式語句的方式來啟動事務。
問:如何避免長事務對業務的影響?
答:
從應用開髮端來看:
- 確認是否使用了 set autocommit=0。
- 確認是否有不必要的只讀事務。
- 業務連接資料庫的時候,通過 SET MAX_EXECUTION_TIME 命令,控制每個語句執行的最長時間,避免單個語句意外執行太長時間。
從資料庫端來看:
- 監控 information_schema.Innodb_trx 表,設置長事務閾值,超過就報警 / 或者 kill;
- Percona 的 pt-kill 工具不錯;
- 在業務功能測試階段要求輸出所有的 general_log,分析日誌行為提前發現問題;
- MySQL 5.6 或者更新版本,把 innodb_undo_tablespaces 設置成 2(或更大的值)。如果真的出現大事務導致回滾段過大,這樣設置後清理起來更方便。