學(xué)習(xí)了基礎(chǔ)架構(gòu), 日志系統(tǒng)。今天看一下,我們平時在日常開發(fā)中用的最多的事務(wù)壁肋。
最經(jīng)典的例子号胚,就是你要給你的朋友王麻子轉(zhuǎn)100塊錢,而此時你的銀行卡中只有100塊錢浸遗。轉(zhuǎn)賬的過程具體到程序里會有一系列的操作猫胁,比如查詢余額、做加減法跛锌、更新余額等操作弃秆。
這些操作必須保證是一體的,不然等程序查完后髓帽,你“趁著程序還沒反應(yīng)過來”進(jìn)行扣減菠赚,你再給另一個朋友轉(zhuǎn)去100元,這豈不是亂套了嗎郑藏?這個時候就要用到 事務(wù) 了衡查。
一、概念
事務(wù)是應(yīng)用程序中一系列嚴(yán)密的操作必盖,所有操作必須成功完成拌牲,否則在每個操作中所作的所有更改都會被撤消。也就是事務(wù)具有原子性歌粥,一個事務(wù)中的一系列的操作要么全部成功塌忽,要么一個都不做。
事務(wù)的結(jié)束有兩種失驶,當(dāng)事務(wù)中的所以步驟全部成功執(zhí)行時土居,事務(wù)提交。如果其中一個步驟失敗嬉探,將發(fā)生回滾操作装盯,撤消撤消之前到事務(wù)開始時的所以操作。
在MySQL中甲馋,事務(wù)是在引擎層進(jìn)行實現(xiàn)的,MySQL是一個支持多引擎的系統(tǒng)迄损,但是并不是所有的引擎都是支持事務(wù)的定躏。MySQL 原生的MyISAM就是不支持事務(wù),這也是MySQL5.5之后芹敌,MyISAM被InnoDB取代的重要原因之一痊远。
二、隔離級別
提到事務(wù)氏捞,我們第一反應(yīng)應(yīng)該就是事務(wù)的四大特性碧聪,原子性(Atomicity)、一致性(Consistency)液茎、隔離性(Isolation)逞姿、持久性(Durability)辞嗡,簡稱 ACID。其他的通過字面意思都還是比較好理解的滞造,我們看下這個 “隔離性”是怎么玩的续室。
我們知道,在數(shù)據(jù)庫上進(jìn)行多個事務(wù)同時執(zhí)行的時候谒养,就可能會出現(xiàn)臟讀(dirty read)挺狰、不可重復(fù)讀(non-repeatable read)、幻讀(phantom read)的問題买窟,為了解決這些問題丰泊,引出了隔離級別這個概念。
Tips:
臟讀:讀到其他事務(wù)未提交的數(shù)據(jù)始绍;
不可重復(fù)讀:前后讀取的記錄內(nèi)容不一致(數(shù)據(jù))瞳购;
幻讀:前后讀取的記錄數(shù)據(jù)不一致(條數(shù));
SQL標(biāo)準(zhǔn)的事務(wù)隔離級別包括:讀未提交(read uncommitted)疆虚、讀提交(red committed)苛败、可重復(fù)讀(repeatable read)、串行化(serialzable)径簿。這些分別都是什么意思呢罢屈?別急,解釋來了:
讀未提交:一個事務(wù)還沒有提交時篇亭,他做的變更數(shù)據(jù)就能被其他的事務(wù)看到缠捌。
讀 提 交 :一個事務(wù)提交之后,他做得變更數(shù)據(jù)才能被其他事務(wù)看到译蒂。
可重復(fù)讀:一個事務(wù)執(zhí)行過程中看到的數(shù)據(jù)曼月,總是跟這個事務(wù)啟動時看到的數(shù)據(jù)是一致的。(在可重復(fù)讀隔離級別下柔昼,未提交的變更對其他事務(wù)是不可見的)哑芹,換句話就是 一個事務(wù)啟動時,讀到的是什么數(shù)據(jù)捕透,在執(zhí)行過程中聪姿,就是什么數(shù)據(jù),不會發(fā)生改變乙嘀,無論別的事務(wù)是否對其進(jìn)行改動末购。
串 行 化 :對同一行數(shù)據(jù)記錄,寫時會加寫鎖虎谢,讀時會加讀鎖盟榴。當(dāng)出現(xiàn)讀寫鎖沖突時,后訪問的事務(wù)必須要等待前一個事務(wù)完成婴噩,才能進(jìn)行擎场。換句話也就是說羽德,我執(zhí)行的時候,別的事務(wù)是不能查詢到或者修改這一行數(shù)據(jù)的顶籽。
舉個例子:
mysql> create table D(a int) engine=InnoDB;insert into D(a) values(1);
insert into D(a) values(1);
看下在不同的隔離級別下玩般,事務(wù)A都會有什么結(jié)果。
讀未提交:V1 的值 是 2 礼饱。事務(wù)B雖然還沒有提交坏为,但是結(jié)果A已經(jīng)看到了,所以V2,V3結(jié)果都是2 镊绪。
讀 提 交 :V2 的值 是 1 匀伏。事務(wù)B提交,但是A是看不到的蝴韭,所以V2 是 1够颠。這時事務(wù)A提交,V3的值 是 2榄鉴。
可重復(fù)讀 :V1 履磨,V2 的值 是 1。V3 的是 2庆尘。V1剃诅,V2之所以是1,就是因為遵循事務(wù)執(zhí)行期間驶忌,看到的數(shù)據(jù)結(jié)果是一致的矛辕。
串 行 化 :事務(wù)A啟動時,進(jìn)行查詢付魔,這時會加讀鎖聊品,事務(wù)B在進(jìn)行讀取,要等到事務(wù)A釋放几苍,才能進(jìn)行讀取翻屈。等到事務(wù)A提交事務(wù),事務(wù)B進(jìn)行執(zhí)行妻坝,這時V1伸眶,V2的值是1,V3的值為2惠勒。
**三、什么時候創(chuàng)建視圖 **
為什么有的是能看到有的卻看不到呢爬坑?因為在實現(xiàn)上纠屋,數(shù)據(jù)庫會創(chuàng)建一個視圖,訪問的時候以視圖的邏輯結(jié)果為準(zhǔn)盾计,進(jìn)行訪問售担。在每個隔離級別下赁遗,視圖創(chuàng)建的時間也是不同的,數(shù)據(jù)庫的行為是有所不同的族铆。
可重復(fù)讀:視圖是在事務(wù)啟動時進(jìn)行創(chuàng)建的岩四,整個事務(wù)存在期間都用這個視圖。
讀 提 交 :視圖是在每個SQL語句開始執(zhí)行時進(jìn)行創(chuàng)建的哥攘。
讀未提交:直接返回記錄上的最新值剖煌,沒有視圖概念。
串 行 化 :采用鎖的機(jī)制來避免并行訪問逝淹。
也就是說耕姊。
讀提交的情況下,會在每一個語句前創(chuàng)建一個視圖栅葡,所以在讀提交情況下茉兰,一個事務(wù)是可以看到其他事務(wù)提交的內(nèi)容,因為它在每次查詢之前都會重新用最新的數(shù)據(jù)創(chuàng)建一個視圖欣簇。
可重復(fù)讀的級別下规脸,視圖是在開始事務(wù)的時候就創(chuàng)建好了,這個視圖會一直使用熊咽,一直到這個事務(wù)結(jié)束莫鸭。
四、事務(wù)隔離的實現(xiàn)
在MySQL中网棍,每條記錄在更新的時候都會記錄一條變更記錄(redo log)黔龟,也同時會記錄一條變更相反的回滾操作記錄(undo log)。
假設(shè)一個值從 2 被按順序改成了3滥玷、4氏身、5,在回滾日志里面就會有類似下面的記錄
( 回滾日志 演示)
當(dāng)前值是4惑畴,不同時刻啟動的事務(wù)會有不同的read-view
在視圖A蛋欣、B、C里面如贷,這一個記錄的值分別是1陷虎、2、4杠袱,同一條記錄在系統(tǒng)中可以存在多個版本尚猿,就是數(shù)據(jù)庫的多版本并發(fā)控制(MVCC)
當(dāng)沒有事務(wù)再需要用到這些回滾日志時,回滾日志會被刪除
同時你會發(fā)現(xiàn)楣富,即使現(xiàn)在有另外一個事務(wù)正在將 4 改成 5凿掂,這個事務(wù)跟 read-view A、B、C 對應(yīng)的事務(wù)是不會沖突的庄萎。
我想你一定有一個疑問踪少,回滾日志總不能一直保留吧,什么時候刪除呢糠涛?
在不需要的時候才刪除援奢。也就是說,系統(tǒng)會判斷忍捡,當(dāng)沒有事務(wù)再需要用到這些回滾日志時集漾,回滾日志會被刪除。****什么時候才不需要了呢锉罐?就是當(dāng)系統(tǒng)里沒有比這個回滾日志更早的 read-view 的時候帆竹。
五、事務(wù)的啟動方式
顯式啟動事務(wù)語句:begin或start transaction脓规,配套的提交語句是commit栽连,回滾語句是rollback
set autocommit=0:該命令會將這個線程的自動提交關(guān)掉,如果你只執(zhí)行一個select語句侨舆,這個事務(wù)就啟動了秒紧,而且并不會自動提交