Innodb支持事務,而myisam不支持事務。
事務的定義:
當多個用戶訪問同一份數據時,一個用戶在更改數據的過程中可能有其他用戶同時發起更改請求,為保證數據的更新從一個一致性狀態變更為另一個一致性狀態,這時有必要引入事務的概念。
Mysql提供了多種引擎支持Innodb和BDB。Innodb存儲引擎事務主要通過UNDO日志和REDO日志實現,Myisam和memory引擎則不支持事務。下圖分別給出三種mysql引擎的區別和特性:
Myisam存儲引擎:由於該引擎不支持事務、也不支持外鍵,所以訪問速度很快。因此對事務完整性沒有要求並以訪問為主的應用適合使用該存儲引擎。
Innodb存儲引擎:
由於該存儲引擎在事務上具有優勢,即支持具有提交、回滾和崩潰恢復能力的事務安裝,所以比myisam存儲引擎占用更多的磁盤空間。因此需要進行頻繁的更新、刪除操作,同時對事務的完整性要求比較高,需要實現並發控制,此時適合使用該存儲引擎。
Memory存儲引擎:
該存儲引擎使用內存來存儲數據,因此該存儲引擎的數據訪問速度非常快,但是安全上沒有保障,(redis也是一個內存存儲引擎)。如果應用中涉及數據比較小,需要進行快速訪問,則適合使用該存儲引擎。
本文主要從以下四個方面來介紹mysql的事務:
- 事務概述
- 事務控制語句
- 事務隔離級別
- innodb鎖機制
事務概述:
事務具有ACID四個性質來保證數據庫的更新從一個一致性狀態到另一個一致性狀態:
原子性(atomicity):事務中所有的操作視為一個原子單元,即對事務所進行的數據修改等操作只能是完全提交或者完全回滾。
一致性(consistency):事務在完成時,必須使所有的數據從一種一致性狀態變更為另外一種一致性狀態,所有的變更都必須應用於事務的修改,以確保數據的完整性。
隔離性(insolation):一個事物中的操作語句所做的修改必須與其他事物所做的修改相隔離。在進行事務查看數據時數據所處的狀態,要么是被另一並發事務修改之前的狀態,要么是被另一並發事務修改之后的狀態,即當前事務不會查看由另外一個並發事務正在修改的數據。這種特性主要由鎖機制實現。
持久性(durability):事務完成之后,所做的修改對數據的影響是永久的,即使系統重啟或者系統出現故障,數據仍可恢復。
REDO日志和UNDO日志:
REDO日志:
事務執行時需要將執行的事務日志寫入到日志文件里,對應的文件為redo日志。當每條sql語句進行數據庫更新操作時,首先將redo日志寫入到日志緩沖區。當客戶端執行commit命令提交時,日志緩沖區的內容將被刷新到磁盤,日志緩沖區的刷新方式或者時間間隔可以通過參數innodb_flush_log_at_trx_commit控制。
REDO日志對應磁盤上的ib_logfileN(ib_logfile0,ib_logfile1)文件,該文件默認為5MB,建議設置為512MB以便容納較大的事務。在mysql崩潰恢復時會重新執行redo日志中的記錄。
UNDO日志:
與redo日志相反,undo日志主要用於事務異常時的數據回滾,具體內容就是復制事務前的數據庫內容到undo緩沖區,然后在合適的時間將內容刷新到磁盤。
與redo日志不同的是,磁盤上不存在單獨的undo日志文件,所有的undo日志文件均存放在表空間對應的.idb數據文件中,undo日志又被成為回滾段。
Mysql事務控制語句:
START TRANSACTION | BEGIN [WORK] //開啟一個事務 COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE] //提交一個事務 ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE] //回滾一個事務 SET AUTOCOMMIT = {0 | 1} //自動提交事務開啟或者關閉
查看事務的隔離級別:
show variables like 'tx_isolation';
例子:commit之后才會對表進行插入
回滾之后,表不會有變動
SET AUTOCOMMIT =1;
當自動提交被打開以后,我們rollback也沒用,會自動提交。
Mysql事務隔離級別
sql標准定義了四種隔離級別,指出了哪些改變其他事務可見,哪些數據改變其他數據不可見。低級別的隔離級別可以支持更高的並發處理,同時占用的系統資源更少。
查看事務的隔離級別:
show variables like 'tx_isolation';
#未提交讀,以下是設置隔離級別語句,更改默認隔離級別,需要重新登錄 SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; #提交讀 SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; #可重復讀 SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ; #可串行化 SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
READ-UNCOMMITTED(讀取未提交內容):
在該隔離級別,所有事物都可以看到其他未提交事務的執行結果。因為其性能也不必其他級別高很多,因此該隔離級別很少使用。讀取未提交的數據被稱為臟讀。
兩個事物在更新前,數據一致,但是左邊的事務還未提交更改,右邊的事務也讀到其更改數據,這種情況稱為臟讀。
READ_COMMITED(讀取提交內容):
這是大多數數據庫默認的隔離級別,但並不是mysql默認的隔離級別。其滿足了隔離的簡單定義:一個事務從開始到提交前所做的任何改變都是不可見的,事務職能看見已經提交的事務所做的改變。
該隔離級別可能導致不可重復讀問題,因為同一事務的其他實例在該實例的處理期間可能會有新的數據提交導致數據改變,所以同一個查詢可能在不同時刻返回不同結果。
以下例子:A事務雖然沒有提交,但是卻看到不同數據。同一事務中,兩次看到的數據是不一致的。
REPEATABLE-READ(可重讀):
這是mysql的默認隔離級別。
該隔離級別能保證同一事務的多個實例在並發讀取數據時,會看到同樣的數據行,理論上會導致另一問題:幻讀。
幻讀:例如事務A對一個表中的數據修改涉及到全部的數據行。此時,事務B對該表插入一個數據行。那么出現的問題就是,該表中出現了事務A還沒有修改的數據行。
Innodb和falcon存儲引擎通過mvcc(多版本控制)機制解決了該問題。
innodb存儲引擎的MVCC機制:innodb通過為每個數據行增加兩個隱含值的方式來實現。這兩個隱含值記錄了行的創建時間,及過期時間。每一行存儲事件發生時的系統版本號,每一次開始一個新的事物,版本號會自動加1,每個事物都會保存開始時的版本號,每個查詢根據事物的版本來查詢結果。
Serializable(可串行化):
這是最高的隔離級別,通過強制事物排序,使之不可能相互沖突,從而解決幻讀問題。簡言之,是在每個讀的數據行上加上共享鎖實現。在這個級別,可能會導致大量的超時現象和鎖競爭,一般不推薦使用。
該隔離級別采用不同的鎖類型來實現。
事務的隱式提交:例如alter table會造成隱式事務提交,盡管我們沒有提交事務,但是在其他事務中卻看到了我們的數據變化。
Innodb的鎖機制:
鎖的類型:
共享鎖:
共享鎖又稱為S鎖,是share的縮寫,共享鎖的鎖粒度是行或者元組(多個行)。一個事務獲取了共享鎖之后,可以對鎖定范圍的數據執行讀操作。
排它鎖:
排它鎖的代號是X,是eXclusive的縮寫,排它鎖的鎖粒度也是行或者元組,一個事務獲取了排它鎖以后,可以對鎖定范圍內的數據執行寫操作。
意向鎖:
意向鎖是一種表鎖,鎖的粒度是整張表,分為意向共享鎖(IS)和意向排它鎖(IX)兩類。意向鎖表示一個事務有意對數據上共享鎖或者排它鎖。”有意“表示事務想執行操作,但還沒有真正執行。
鎖和鎖之間要么是相容的,要么是互斥的:
鎖粒度:
鎖的粒度主要分為行鎖和表鎖。鎖的粒度越小,其耗費的系統資源越多,但是並發性卻更好。
表鎖的開銷最小,同時允許的並發量也是最小的鎖機制。Myisam使用該鎖機制。
行鎖支持最大的並發,innodb存儲引擎使用該鎖機制,如果支持並發讀寫,建議采用innodb鎖機制。
select語句會加上一個共享鎖,如果查找的數據已經被加上排它鎖的話,共享鎖會等待期結束再加,若等待時間過長就會顯示需要等待的鎖超時。
insert、update、delete會被加上排它鎖。