做為開發人員對資料庫事務應該都不陌生,但是如果知其然而不知其所以然的話,在開發中難免寫出來的**存在bug,本文主要介紹mysql中的事務,重點講解事務的隔離級別。
1. acid
1.1 原子性
原子性是指事務是乙個不可分割的工作單位,事務中的操作要麼全部執行,要麼全部都不執行。
例如:begin // 開啟事務
a:update user set account=account+1 where id =1;
b:update user set account=account+1 where id =1;
commit
這個事務,執行commit時,在麼兩條語句都執行成功,如果出錯,執行rollback時,兩條語句的操作都會回滾到原始狀態;
undo log保證原子性
在操作任何資料之前,首先將資料備份到乙個地方(這個儲存資料的地方就是undo log)。然後進行資料的修改,如果使用者出現了錯誤或者使用者執行了rollback語句,系統可用利用undo log中的備份的資料恢復到事務開始之前的狀態。
注意:undo log是邏輯日誌
可以理解為:
當delete一條記錄時,undo log中記錄一條對應的insert記錄
當insert 一條記錄時,undo log中會記錄一條對應的delete記錄
當update一條記錄時,它記錄一條對應相反的udpate記錄
1.2 一致性
事務執行前和事務執行後,資料庫的完整性約束不被破壞。即事務的執行是從乙個有效狀態轉移到另乙個有效狀態;
例如:tom給jack轉賬50元,如果從tom賬戶減少後系統故障或其它原因沒有給jack加上50元,而事務還沒有執行完畢,資料庫會將整個轉賬過程回滾,保證資料的一致性;
1.3 隔離性
隔離性是指在併發操作中,不同事務之間應該隔離開來,使每個併發中的事務不會互相干擾;
1.4 持久化
一旦事務提交成功,事務中所有的資料操作都必須被持久化儲存到資料庫中,即使提交事務後,資料庫崩潰,在資料庫重啟時,也必須能保證通過某種機制恢復資料。
redo log保證永續性
redo log記錄的是新資料的備份,在事務提交前,只要將redo log持久化即可,不需要將資料持久化。當系統崩潰時,雖然資料沒有持久化,但是redo log已經持久化,系統可以根據redo log的內容,將所有資料恢復到最新的狀態。
2. 事務引起的問題
2.1 髒讀
事務a讀取到了事務b已經修改但尚未提交的資料,如果事務b回滾,a讀取的資料與上次不一致;不符合事務的一致性要求;
例如:a(圖左)和b(圖右)同時開啟事務,a執行如下命令:
使用者a並未提交事務,可見在事務b中兩次查詢的結果已經發生變化,讀取了事務a中未提交的資料;
2.2 不可重複讀
事務a讀取到了事務b已經提交的修改資料,不符合隔離性;
上圖可見,事務b讀取到了事務a所修改的資料;
2.3 幻讀
事務a讀取到了事務b提交的新增資料,不符合隔離性;
事務b讀取到了事務a提交的新增資料;
3. 深入隔離級別
隔離級別等級:
檢視隔離級別:
show variables like '%isolation%';
select @@global.transaction_isolation, @@transaction_isolation;
設定隔離級別:
全域性:set global transaction isolation level repeatable read;
會話:set session transaction isolation level repeatable read;
3.1 讀未提交
讀未提交是資料庫事務隔離級別最低的級別,它任何問題都沒有解決;
設定資料庫事務隔離級別為讀未提交
3.2 讀已提交
讀已提交它主要解決髒讀的問題;
設定資料庫事務隔離級別為讀已交
可以看出,讀已提交已經解決了髒讀的問題;
3.3 可重複讀
設定事務隔離級別:
可以看到,就算事務a已經提交,事務b也不會再讀到事務a提交的資料;
那麼可重複讀是否解決了幻讀呢?
我們試驗一下:
這是怎麼回事呢?不是說好的可重複讀不會解決幻讀的問題嗎?為什麼這裡新插入的資料就是沒有在事務b中讀取到呢? (下節解答)
3.4 序列化
序列化就不多說了,它其實是將事務按排隊的處理方式,但是這樣會使事務非常低率的。
4. mysql的mvcc
我們先來看個示例:
從上面的執行過程可以看出,在a事務提交之後,b事務雖然執行查詢時沒有 問題,但是在b事務執行更新之後,再查詢時,賬戶直接少了100;這是為什麼呢?
1) mvcc原理
innodb的mvcc通過每行記錄後面的兩個隱藏欄位來實現的,建立時的版本號和刪除時的版本號。每個事務開始版本號都會遞增。
select:
查詢版本早於當前事務版本的資料行,即,行的系統版本號小於或等於事務的系統版本號,這樣可以確保事務讀取的行,是在事務開始之前已經存在的或者自身事務操作過的。
行的刪除版本,要麼未定義,要麼大於當前事務版本號,這樣可以確保事務讀取到的行,在事務開始之前未被刪除;
insert:
為插入的每一行儲存當前系統版本號作為行的版本號;
delete:
刪除的每行儲存當前系統版本號作為刪除標記;
update:
插入一行新記錄,儲存當前系統版本號為行版本號,同時,儲存當前系統版本號到原來的行的刪除標識;
2) 快照讀和當前讀
快照讀:
讀取的是快照版本,也就是歷史版本;普通的select就是快照讀
當前讀:
讀取的是最新版本,update、delete、insert、select...lock in share mode、select ... for update是當前讀;
3.3節疑惑解答
事務a執行更新之後,提交了事務,而事務b再執行更新的時候,它其實是乙個當前讀,能夠讀取到最新的已經被事務a修改後的資料(前提事務a已經提交)。
3) undo log中的版本鏈及readview
mysql 索引深入理解 深入理解MySql的索引
為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...
MySQL深入理解
儲存引擎 innodb表引擎 myisam表引擎 其他的表引擎 索引 索引對效能的影響 索引的使用場景 索引的型別 對比說明 mysql索引的建立原則 mysql索引的注意事項 查詢優化 查詢分析sql查詢慢的原因 優化查詢過程中的資料訪問 避免使用如下sql語句 是否在掃瞄額外的記錄?優化長難的查...
mysql深入理解二
過濾資料 本章講授如何使用select語句的where 子句指定的搜尋條件。資料庫表一般包含 大量的資料,很少需要檢索表中所有的行。通常只會根據特定操作或報告的需要 提取資料的子集。只檢索所需資料需要的指定搜尋條件 search criteria 搜尋條 件也稱為過濾條件 filter condit...