事务隔离机制原理分析以及是否可以防止订单超卖
事務(wù)的隔離機(jī)制是指:
Read Uncommitted(讀取未提交內(nèi)容)
Read Committed(讀取提交內(nèi)容)
Repeatable Read(可重讀)
Serializable(可串行化)
具體的解釋最經(jīng)典的MySQL書(shū)《高性能MySQL(第3版)》已經(jīng)有了就不在其他地方再引用了:
隔離機(jī)制的比較
其實(shí)也有人喜歡用鎖來(lái)控制并發(fā),書(shū)中還提到了“隱式”和“顯示鎖定”,是這么建議的:
雖然這樣,但是其實(shí)如果不經(jīng)過(guò)實(shí)際的演練還是很難理解上面說(shuō)的事務(wù)隔離機(jī)制到底怎么樣可以防止并發(fā)。
1.查看MySQL版本
我們的版本是5.1.7
2.查看存儲(chǔ)引擎
>show engines;
存儲(chǔ)引擎是:InnoDB
3.實(shí)驗(yàn)表
假設(shè)有個(gè)商品表g,關(guān)鍵字段num表示庫(kù)存,name表示商品名稱(chēng)
主要就是看不同事務(wù)隔離機(jī)制下并發(fā)修改庫(kù)存是否會(huì)出現(xiàn)超賣(mài)。
假設(shè)我們的程序需要先查詢(xún)庫(kù)存,如果庫(kù)存>0都可以賣(mài),update扣庫(kù)存,否則rollback。
為了制造并發(fā)肯定需要2個(gè)事務(wù),假設(shè)是A和B。
4.確認(rèn)事務(wù)隔離機(jī)制
修改會(huì)話(huà)的事務(wù)隔離級(jí)別
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
>select @@global.tx_isolation,@@tx_isolation;
5.Serializable
場(chǎng)景一:
顯然一開(kāi)始AB查詢(xún)的數(shù)據(jù)是一樣的num=1
A開(kāi)始update
這時(shí)候在等待,無(wú)法update。
過(guò)一會(huì)就超時(shí)了。
如果這個(gè)時(shí)候B也update那么一樣會(huì)等待超時(shí)
所以這樣,AB就會(huì)都超時(shí)。
這時(shí)即使commit也是返回0,數(shù)據(jù)庫(kù)不會(huì)變化。
場(chǎng)景二:
A在update等待的時(shí)候,B馬上commit,但是B沒(méi)有update
查看結(jié)果
這次A成功的扣庫(kù)存。
所以從上面可以得出一個(gè)結(jié)論:serializable是可以很好的控制并發(fā)。
然后需要把庫(kù)存改為1,便于測(cè)試。
6.read committed
>set session transaction isolation level read committed;
>select @@global.tx_isolation,@@tx_isolation;
場(chǎng)景三:
初始化AB查出來(lái)的庫(kù)存都是1,然后A可以u(píng)pdate一條數(shù)據(jù),無(wú)等待。
這時(shí)候AB再比較下庫(kù)存,A已經(jīng)是0,B是1,因?yàn)锳沒(méi)有commit。
然后A執(zhí)行commit操作,這時(shí)候B再查已經(jīng)是庫(kù)存0;
這時(shí)候B執(zhí)行update返回是0行,因?yàn)閡pdate不能滿(mǎn)足where條件,所以B只有Commit,然后重新提交。
場(chǎng)景四:
一開(kāi)始AB都是一樣的庫(kù)存1,然后A開(kāi)始update,然后A的庫(kù)存是0,B是1,因?yàn)锳還沒(méi)有提交。
這時(shí)候B再u(mài)pdate
按照前面的經(jīng)驗(yàn),B等待其實(shí)是再等A提交,A如果一直不提交,B就會(huì)超時(shí)。
這時(shí)A提交commit,B查詢(xún)就得到A更新后的結(jié)果,這時(shí)B查到庫(kù)存是0自然不會(huì)去更新,也就只能結(jié)束事務(wù)。
場(chǎng)景五:
AB先后update,然后A在B超時(shí)之前commit,這時(shí)由于B已經(jīng)讀到A更新后的結(jié)果0,所以B就不能成功update。
7.repeatable read
>set session transaction isolation level repeatable read;
>select @@global.tx_isolation,@@tx_isolation;
場(chǎng)景六:
然后A開(kāi)始update,然后A和B分別讀到庫(kù)存是1和0
然后A提交commit,這時(shí)候再查看A和B的庫(kù)存還是保持不變。
這時(shí)候B再次嘗試update
依然是返回0條,說(shuō)明更新不成功。
場(chǎng)景八:
AB同時(shí)update
如果A不及時(shí)commit那么B肯定會(huì)超時(shí)
場(chǎng)景九:
就是場(chǎng)景八A及時(shí)commit
如果A及時(shí)commit
所以可以看出無(wú)論是read committed還是repeatable read只要update的條件where ?num>0足夠充分都是可以控制并發(fā)防止超賣(mài)的。
如果沒(méi)有帶where ?num>0這個(gè)控制條件,那么肯定會(huì)可以u(píng)pdate成功的。
8.read uncommitted
這個(gè)是需要杜絕的,就不討論了。
9.如果沒(méi)有帶where ?num>0,那么會(huì)怎么樣呢。其實(shí)只要理解了上述流程就可以想明白會(huì)怎么樣。
對(duì)于read committed
A已經(jīng)update,B讀到庫(kù)存是0自然不會(huì)去更新;
A沒(méi)有update,B讀到庫(kù)存是1,這要看A會(huì)不會(huì)及時(shí)提交;
如果A及時(shí)提交,B自然會(huì)去更新因?yàn)闈M(mǎn)足where條件,且成功,這樣就超賣(mài)-1;
這時(shí)候由于B沒(méi)有提交,所以AB分別查出0和-1
然后B提交commit,AB查出的都是-1,就不演示了。
修改會(huì)話(huà)為repeatable read
AB先后update,B在等待
然后A立即提交commit,B馬上update得到返回。
結(jié)果就是-1產(chǎn)生了超賣(mài):
總結(jié):
1.使用serializable是可以防止超賣(mài),但是性能怎么樣需要數(shù)據(jù)說(shuō)明;
2.read committed和repeatable read帶上where條件庫(kù)存num>0都是可以防止超賣(mài)的,不過(guò)需要處理超時(shí)。
3.其他各種組合情況還會(huì)更復(fù)雜,具體具體問(wèn)題具體分析。
總結(jié)
以上是生活随笔為你收集整理的事务隔离机制原理分析以及是否可以防止订单超卖的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Spring源码分析【8】-分布式环境S
- 下一篇: JVM内存溢出的几种情形