中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

MYSQL事務(wù)隔離級(jí)別

2018-07-31    來(lái)源:importnew

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

本文會(huì)根據(jù)實(shí)際工作中碰到的例子,梳理清楚數(shù)據(jù)庫(kù)事務(wù)的隔離級(jí)別。內(nèi)容很簡(jiǎn)單,如果你能靜下心來(lái)看完,一定會(huì)對(duì)你理解隔離級(jí)別有很大的幫助。

想象一個(gè)場(chǎng)景。抽獎(jiǎng),如果用戶中獎(jiǎng)了,一般有如下幾個(gè)流程:

  • 扣減獎(jiǎng)品數(shù)量;
  • 記錄用戶中獎(jiǎng)信息;
  • 試想如果扣減獎(jiǎng)品數(shù)量了,結(jié)果記錄用戶中獎(jiǎng)數(shù)據(jù)的時(shí)候失敗了,那么數(shù)據(jù)就會(huì)出現(xiàn)不一致的問(wèn)題。

這種場(chǎng)景,就可以使用事務(wù)。因?yàn)槭聞?wù)的一個(gè)特性,就是原子性:要么不做,要么全做。

上述問(wèn)題解決了。再想一下這樣的場(chǎng)景:
在抽獎(jiǎng)前,先查詢獎(jiǎng)品剩余數(shù)量,如果剩余數(shù)量<1,則任務(wù)抽獎(jiǎng)活動(dòng)已經(jīng)結(jié)束,不再進(jìn)行抽獎(jiǎng)。如果事務(wù)A扣減獎(jiǎng)品數(shù)量但未提交,事務(wù)B查詢剩余獎(jiǎng)品數(shù)量,此時(shí)應(yīng)該是多少呢?這就和事務(wù)的隔離級(jí)別有關(guān)系了。

在討論隔離級(jí)別前,我們先做一些數(shù)據(jù)庫(kù)的初始化操作:

建表:

CREATE TABLE `Tran_test` (
  `id` bigint(20) NOT NULL,
  `userId` bigint(20) NOT NULL DEFAULT '0',
  `weChatId` varchar(50) NOT NULL DEFAULT '' COMMENT '微信id(openId、uninId)',
  `orderId` bigint(20) NOT NULL DEFAULT '0' COMMENT '商城訂單id',
  `count` bigint(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

初始化1個(gè)獎(jiǎng)品:

insert into Tran_test (id,count) values(1,1)

未提交讀

事務(wù)中的修改,即使沒(méi)有提交,也會(huì)被其他事務(wù)讀取。

下面通過(guò)mysql演示:

設(shè)置隔離級(jí)別為為提交讀:

SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

可以看到,事務(wù)B讀取到了事務(wù)A未提交的數(shù)據(jù),它任務(wù)抽獎(jiǎng)活動(dòng)已經(jīng)結(jié)束。但如果此時(shí)事務(wù)A回滾,count仍然為1,則活動(dòng)實(shí)際是未結(jié)束的,這就是臟讀。因此,實(shí)際中,一般不會(huì)采用這種隔離級(jí)別。

提交讀

提交讀隔離級(jí)別可以解決上述臟讀問(wèn)題,其只能讀到其他事務(wù)已經(jīng)提交的數(shù)據(jù)。

更改數(shù)據(jù)庫(kù)隔離級(jí)別:

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

可以看到,在事務(wù)A提交前的改動(dòng),事務(wù)B是讀取不到的。只有A事務(wù)提交后,B才能讀取到事務(wù)A的改動(dòng)。

我們看到,在事務(wù)B中,先后兩次讀取,count的值是不一樣的,這就是不可重復(fù)讀。而可重復(fù)讀隔離級(jí)別可以解決這個(gè)問(wèn)題。

可重復(fù)讀

更改數(shù)據(jù)庫(kù)隔離級(jí)別:

SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

可以看到,不論事務(wù)A是否提交,事務(wù)B讀到的count值都是不變的。這就是可重復(fù)讀。

除了上面提到的臟讀、不可重復(fù)讀,還有一種情況是幻讀:在事務(wù)中,前后兩次查詢,記錄數(shù)量是不一樣的。

比如事務(wù)B是事務(wù)A插入一條記錄的前后執(zhí)行查詢,會(huì)發(fā)現(xiàn)相同的查詢條件,查出來(lái)的記錄數(shù)不一樣。由于mysql的RR(可重復(fù)讀)一并解決了幻讀的問(wèn)題,所以我們直接看上述場(chǎng)景,在mysql中的表現(xiàn):

可見(jiàn),在事務(wù)A提交前后,事務(wù)B查詢的結(jié)果數(shù)量是一直的,并沒(méi)有出現(xiàn)幻讀的情況。

一點(diǎn)思考

下面默認(rèn)都是討論的msyql RR隔離級(jí)別的情況。

如果兩個(gè)用戶同時(shí)抽獎(jiǎng),而且同時(shí)中獎(jiǎng)。兩者都進(jìn)入了中獎(jiǎng)的事務(wù)。A事務(wù)扣減了獎(jiǎng)品數(shù)量,B也執(zhí)行了扣減數(shù)量。假設(shè)獎(jiǎng)品數(shù)量是N,如果是可重復(fù)讀,那么,如果兩個(gè)事務(wù)并行進(jìn)行,那么不論A有沒(méi)有提交,B讀到的數(shù)量都是N,執(zhí)行后為N-1,而事務(wù)A也是N-1,這樣不就有問(wèn)題了嗎?我們期望的是N-2。

當(dāng)初這個(gè)問(wèn)題讓我很困惑。這反應(yīng)了當(dāng)時(shí)我對(duì)數(shù)據(jù)庫(kù)鎖和快照讀、當(dāng)前讀兩個(gè)知識(shí)點(diǎn)的欠缺。

快照讀、當(dāng)前讀

將設(shè)事務(wù)A已經(jīng)提交,由于是可重復(fù)讀,那事務(wù)B讀到的獎(jiǎng)品數(shù)量一致是N,執(zhí)行-1,數(shù)據(jù)變成N-1,而不是我們期望的N-2。

如果理解了快照讀和當(dāng)前讀的概念,上面的困惑就不會(huì)存在了。

在事務(wù)中,執(zhí)行普通select查詢之后,會(huì)創(chuàng)建快照,后面再執(zhí)行相同的select語(yǔ)句時(shí),查詢的其實(shí)是前面生成的快照。這也就是為什么會(huì)有可重復(fù)讀。

而如果執(zhí)行

select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…); 
update table set ? where ?; 
delete from table where ?;

會(huì)執(zhí)行當(dāng)前讀,獲取最新數(shù)據(jù);氐角懊娴膯(wèn)題,如果事務(wù)B執(zhí)行N-1操作,會(huì)觸發(fā)當(dāng)前讀,讀取事務(wù)A提交后的數(shù)據(jù),也就是N-1,在此基礎(chǔ)上執(zhí)行-1操作,最終N變成N-2。

并發(fā)更新

上面解決了事務(wù)A已經(jīng)提交的額情況。但如果事務(wù)A更新獎(jiǎng)品數(shù)量后但還未提交呢?此時(shí)事務(wù)B執(zhí)行當(dāng)前讀拿到的也是N啊。了解數(shù)據(jù)庫(kù)鎖機(jī)制的話,就不會(huì)有這種困惑了。事務(wù)A提交前,會(huì)一直持有排他鎖(具體是行鎖還是表鎖,要看查詢條件有沒(méi)有走索引),此時(shí)事務(wù)B更新是會(huì)阻塞的。也就是說(shuō),只有事務(wù)A提交,或回滾之后,事務(wù)B才能獲得排它鎖,從而進(jìn)行更新獎(jiǎng)品的操作。

關(guān)于數(shù)據(jù)庫(kù)的鎖,大家可以參考這篇文章:http://hedengcheng.com/?p=771

標(biāo)簽: Mysql 數(shù)據(jù)庫(kù)

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:深入理解單例模式(上)

下一篇:JVM面試題