一個事務會涉及到大量的cpu計算和IO操做,這些操做被打包成一個執行單元,要麼同時都完成,要麼同時都不完成.mysql
事務是一組原子性的sql命令或者說是一個獨立的工做單元,若是數據庫引擎可以成功的對數據庫應用該組的所有sql語句,那麼就執行該組命令sql
若是其中有任何一條語句由於崩潰或者其它緣由沒法執行,那麼該組中全部的sql語句都不會執行數據庫
若是沒有顯示啓動事務,數據庫會根據autocommit的值.默認每條sql操做都會自動提交.安全
一個事務中的全部操做,要麼都完成,要麼都不執行.對於一個事務來講,不可能只執行其中的一部分.服務器
數據庫老是從一個一致性的狀態轉換到另一個一致性狀態.併發
一個事務所作的修改在最終提交之前,對其它事務是不可見的.多個事務之間的操做相互不影響. 每下降一個事務隔離級別都能提升數據庫的併發mvc
1.讀未提交 其它事務未提交就能夠讀
2.讀已提交 其它事務只有提交了才能讀
3.可重複讀 只管本身啓動事務時候的狀態,不受其它事務的影響(mysql默認)
4.事務串行 按照順序提交事務保證了數據的安全性,但沒法實現併發ide
一旦一個事務已經提交了,就算服務器崩潰,仍然須要在下次啓動的時候自動恢復.性能
結合事務日誌完成:設計
事務日誌寫入磁盤的時候是順序IO,寫數據文件的時候是隨機IO
一旦事務提交了,必須當即執行一個IO操做,確保此事務當即寫入磁盤.
事務的狀態
活動
部分提交
失敗
停止
提交
事務一旦成功提交,便沒法再撤銷.
事務併發訪問控制方式:
鎖
時間
多版本和快照隔離(mvcc)
MVCC是行級鎖的一個變種,可是它在不少狀況下避免了加鎖操做,所以開銷更低,雖然實現機制有所不一樣,但大都實現了非阻塞的讀操做,寫操做也只鎖定必要的行.
MVCC的實現是經過保存數據在某個時間點的快照來實現的,也就是說,無論須要執行多長時間,只要事務開始時間相同,每一個事務看到的數據都是一致的,事務開始的時間不一樣時,每一個事務對同一張表,同一時刻看到的數據多是不同的(由於不一樣的時間點可能數據就已經產生了不一樣的快照版本,而每一個事務在默認的RR隔離級別下只能看到事務開始時的數據快照)
innodd的mvcc是經過在每行記錄後面保存兩個隱藏列來實現的.這兩個列,一個保存了行的建立時間.一個保存了行的過時時間(刪除時間).列裏面存儲的並非實際的時間值.而是系統版本號.每開啓一個新的事務,系統版本號都會自動遞增.
一個事務在開啓的時刻的系統版本號做爲當前事務的版本號,用來和查詢到的每行記錄的版本號作對比.mvcc具體操做以下:
select:
A:過濾建立版本
innodb只查找版本早於當前事務版本的數據行(也就是,行的系統版本號小於或等於事務的系統版本號),這樣能夠確保事務讀取的行,要麼是在事務開始以前已經存在,要麼是事務自身插入或修改的數據.
B: 過濾刪除版本
行的刪除版本要麼未定義,要麼大於當前事務版本號,這能夠確保事務讀取到的行,在事務開始以前未被刪除(即,這樣作的目的是爲了事務不會讀取到被真正刪除的行,刪除版本號小於當前事務版本號的表示操做刪除記錄的事務已經提交--數據已經被刪除,刪除版本號大於當前事務版本號的表示這個事務是在當前事務以後開始的--當前事務開始時這些記錄是還存在的,根據事務的隔離性,一致性要求,以後開始的事務操做的記錄並提交,對當前事務不可見,因此還須要當前事務可以查詢這些記錄--只可以查詢,不可以修改和刪除)
只有知足以上兩個條件的才能夠返回做爲查詢結果
insert:
innodb爲新插入的每一行保存當前系統版本號做爲行版本號
delete:
innodb爲刪除的每一行保存當前系統版本號做爲行刪除標識
update:
innodb爲插入一行新記錄,保存當前系統版本號做爲行版本號
修改表中原來行把當前系統版本號更新到原來的行做爲行刪除版本號
保存這兩個額外的系統版本號,使大多數讀操做均可以不用加鎖,這樣設計使得讀數據操做很簡單,性能很好,而且也能保證只會讀取到符合標準的行,不足之處是每行記錄都須要額外的存儲空間,須要作更多的行檢查工做,以及一些額外的維護工做。
MVCC只在repeatable-read和read-committed兩個隔離級別下才工做,其餘兩個隔離級別都和MVCC不兼容,由於read uncommitted老是讀取最新的數據行,而不是符合當前事務版本的數據行,而serializeble則會對全部讀取的行都加鎖。
另外要注意:MVCC在RR和RC隔離級別下的區別,在RR隔離級別下,一個事務只能讀取到事務開始的那個時刻的數據快照,即,別的事務修改並提交的數據在自身沒有提交以前通常讀取不到(加for update語句的select除外,由於這個語句要對數據加X鎖必須讀取最新的數據快照),在RC隔離級別下,事務老是讀取數據行的最新快照,即會產生不可重複讀的問題。
兩個或者多個事務在同一資源上相互佔用,並請求鎖定對方佔用的資源的狀態
mysql默認採用自動提交(AUTOCOMMIT)模式.若是沒有顯示的開始一個事務,那麼每條sql語句都會被看成一個事務執行提交的操做
當AUTOCOMMIT=0的時候全部的sql語句都是在一個事務中,直到顯示的執行COMMIT和ROLLBACK回滾該事務結束.同時又開始了另一個新的事務.
開啓事務
START TRANSACTION
結束事務
(1) COMMIT: 提交
(2) ROLLBACK: 回滾
注意:一旦一個事務成功提交,將沒法回滾.一個事務要想回滾,只能在沒有提交成功以前執行回滾
只有事務型存儲引擎中的DML語句方能支持此類操做
建議:顯式請求和提交事務,而不要使用「自動提交」功能 set autocommit={1|0}
事務支持保存點 savepoint:
SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier
RELEASE SAVEPOINT identifier
事務要保證ACID的完整性必須依靠事務日誌作跟蹤,每個操做在真正寫入數據數據庫以前,先寫入到日誌文件中
如要刪除一行數據會先在日誌文件中將此行標記爲刪除,可是數據庫中的數據文件並無發生變化.
只有在(包含多個sql語句)整個事務提交後,再把整個事務中的sql語句批量同步到磁盤上的數據庫文件
在事務引擎上的每一次寫操做都須要執行兩遍:
1.先寫入日誌文件中
寫入日誌文件中的僅僅是操做過程,而不是操做數據自己,因此速度比寫數據庫文件速度要快不少.
2.而後再寫入數據庫文件中
寫入數據庫文件的操做是重作事務日誌中已提交的事務操做的記錄.
日誌組
通常不止設置一個日誌文件,一個文件寫滿以後使用另一個日誌文件提升服務器效率.
日誌文件的日誌同步到磁盤後空間會自動釋放,單個日誌文件不宜設置過大 若是日誌文件過大mysql進程在把日誌同步到數據文件的時候可能會崩潰
事務日誌能夠幫助提升事務的效率,使用事務日誌,存儲引擎在修改表的數據的時候只須要修改其內存拷貝,再把該行爲記錄到持久在磁盤的事務日誌中.而不用每次都將修改的數據自己持久到磁盤.事務日誌採用的是追加方式,所以寫日誌的操做是磁盤上一小塊區域的順序IO,而不像隨機IO須要磁盤在多個地方移動.因此採用事務日誌的方式相對來講要快的多,事務日誌持久後,內存中的修改在後臺慢慢的刷回磁盤.期間若是系統發生崩潰,存儲引擎在重啓的時候依靠事務日誌自動恢復這部分被修改數據