事務(wù)特性ACID
原子性(Atomicity):事務(wù)作為一個(gè)整體被執(zhí)行,包含在其中的對數(shù)據(jù)庫的操作要么全部被執(zhí)行,要么都不執(zhí)行。
一致性(Consistency):事務(wù)應(yīng)確保數(shù)據(jù)庫的狀態(tài)從一個(gè)一致狀態(tài)轉(zhuǎn)變?yōu)榱硪粋€(gè)一致狀態(tài)。一致狀態(tài)的含義是數(shù)據(jù)庫中的數(shù)據(jù)應(yīng)滿足完整性約束。
隔離性(Isolation):多個(gè)事務(wù)并發(fā)執(zhí)行時(shí),一個(gè)事務(wù)的執(zhí)行不應(yīng)影響其他事務(wù)的執(zhí)行。
持久性(Durability):已被提交的事務(wù)對數(shù)據(jù)庫的修改應(yīng)該永久保存在數(shù)據(jù)庫中。
事務(wù)的原子性、一致性、持久性是通過redo/undo log來實(shí)現(xiàn)的
事務(wù)的隔離性是通過鎖來實(shí)現(xiàn)的
事務(wù)理解
持久性理解
首先來看一下事務(wù)的持久性,也許你會(huì)問,事務(wù)的持久性:難道不應(yīng)該等待數(shù)據(jù)最終寫到數(shù)據(jù)文件中完成持久化嗎?
是的,確實(shí)是這樣,而且如果等數(shù)據(jù)最終寫到數(shù)據(jù)文件中標(biāo)志事務(wù)結(jié)束,這樣絕對確保了事務(wù)的持久性,而且根本不需要什么redo log!
按照上述理解,梳理一下事務(wù)的基本流程:
1,事務(wù)開啟
2,先從磁盤中將需要變更的數(shù)據(jù)讀入至內(nèi)存
3,在內(nèi)存中將數(shù)據(jù)更新
4,寫binlog,并刷到磁盤中
5,將內(nèi)存中更改后的數(shù)據(jù)刷至數(shù)據(jù)文件
6,事務(wù)提交成功
這種流程的瓶頸在于第5步,由于數(shù)據(jù)寫到數(shù)據(jù)文件是IO隨機(jī)寫,速度是非常慢的,所有事務(wù)的提交將阻塞在這個(gè)過程??梢岳斫饧僭O(shè)update.. where id=1, update.. where id=999,這樣兩條數(shù)據(jù)之前是分布在不同的磁盤區(qū)域中,現(xiàn)在需要先進(jìn)行查找再寫入,這是非常慢的。
于是innodb做了一系列優(yōu)化,在第5步,這里不是等數(shù)據(jù)寫回至數(shù)據(jù)文件,而是用寫redo log來替代。redo log是一種物理日志,類似于內(nèi)存快照,以追加的方式記錄,是順序IO,寫入速度是非常快的。
所以,真正的事務(wù)并不會(huì)等到數(shù)據(jù)真正寫入數(shù)據(jù)中才返回,引入真正的事務(wù)提交過程:
事務(wù)提交
insert into values( ...);
1、從數(shù)據(jù)庫將需修改數(shù)據(jù)讀入內(nèi)存中Buffer Pool(下圖中無需讀入數(shù)據(jù),已忽略)
2、在內(nèi)存中寫undolog
3、在內(nèi)存中更新數(shù)據(jù),產(chǎn)生臟頁Dirty Page(此時(shí)與數(shù)據(jù)文件中的內(nèi)容不一致)
4、將事務(wù)過程中的變更寫入redo log
5、事務(wù)提交,寫bin log
6、redo log 第二階段,如果5寫入成功則commit(即寫入提交成功的標(biāo)志),否則rollback
后臺線程刷磁盤操作(undolog和數(shù)據(jù)文件的刷入):
1、將undolog 寫入磁盤
2、將數(shù)據(jù)寫入磁盤
我們知道undo log用于事務(wù)的回滾的,理論上跟redo log一樣,也必須在事務(wù)提交之前寫入磁盤的,而且必須在redo log之前寫入!但是仔細(xì)看下面淘寶丁奇大神的圖,會(huì)發(fā)現(xiàn)undo log的寫入并不需要在事務(wù)提交之前完成。這是為何?實(shí)際上Undo和Redo Log的這種關(guān)聯(lián),使得持久化變得復(fù)雜起來。
于是innodb又又作了寫優(yōu)化:將Undo Log看作數(shù)據(jù),因此記錄Undo Log的操作也會(huì)記錄到redo log中。這樣undo log就可以象數(shù)據(jù)一樣緩存起來,而不用在redo log之前寫入磁盤了。
包含Undo Log操作的Redo Log,看起來是這樣的:
記錄1: trx1, Undo log insert undo_insert …
記錄2: trx1, insert …
記錄3: trx2, Undo log insert undo_update …
記錄4: trx2, update …
記錄5: trx3, Undo log insert undo_delete …
記錄6: trx3, delete …
所以,undolog 由后臺線程寫入,不用在redo log之前寫盤了,不過還是必須在數(shù)據(jù)寫入磁盤之前寫入。

事務(wù)與日志
binlog
文件:mysql-bin.000001,mysql-bin.000002..
目的:mysql server層的日志,屬于邏輯日志,記錄的是變更的sql語句,用于數(shù)據(jù)庫宕機(jī)恢復(fù),主備復(fù)制等
log_bin=/var/lib/mysql/binlog/mysql-bin
redo log
文件:ib_logfile*文件,
目的:持久性,參照事務(wù)提交過程
innodb_log_group_home_dir=./logs/redolog(./是mysqlld根目錄)
undo log
文件:默認(rèn)存放在共享表空間內(nèi),ibdata*文件,磁盤上不存在單獨(dú)的undo log文件,
? ? ? 5.6以后也可以設(shè)置為獨(dú)立的文件:innodb_undo_tablespaces
目的:比較好理解,保存的是變更發(fā)生之前的數(shù)據(jù),用于回滾
參考:
http://9i9icenter.com/huanqiuNews/599f30ca2277046518e85878
https://www.slideshare.net/mryufeng/mysqlio-12891332
http://www.zhdba.com/mysqlops/2012/04/06/innodb-log1/