關(guān)于mysql數(shù)據(jù)庫(kù)鎖的完全解讀

一、事務(wù)簡(jiǎn)介

1、事務(wù)簡(jiǎn)介

事務(wù)(Transaction) 是指作為單個(gè)邏輯工作單元執(zhí)行的一系列操作溃蔫。

2、事務(wù)的特性

A琳猫、原子性(Atomicity)

表示組成一個(gè)事務(wù)的多個(gè)數(shù)據(jù)庫(kù)操作是一個(gè)不可分隔的原子單元伟叛,只有所有的操作執(zhí)行成功,整個(gè)事務(wù)才提交脐嫂,事務(wù)中任何一個(gè)數(shù)據(jù)庫(kù)操作失敗统刮,已經(jīng)執(zhí)行的任何操作都必須撤銷(xiāo),讓數(shù)據(jù)庫(kù)返回到初始狀態(tài)账千。

B侥蒙、一致性(Consistency)

事務(wù)操作成功后,數(shù)據(jù)庫(kù)所處的狀態(tài)和它的業(yè)務(wù)規(guī)則是一致的匀奏,即數(shù)據(jù)不會(huì)被破壞鞭衩。

C、隔離性(Isolation)

在并發(fā)數(shù)據(jù)操作時(shí),不同的事務(wù)擁有各自數(shù)據(jù)空間论衍,它們的操作不會(huì)對(duì)對(duì)方產(chǎn)生干擾恒水。數(shù)據(jù)庫(kù)規(guī)定了多種事務(wù)隔離級(jí)別,不同隔離級(jí)別對(duì)應(yīng)不同的干擾程度饲齐,隔離級(jí)別越高钉凌,數(shù)據(jù)一致性越好,但并發(fā)性越弱捂人。

D御雕、持久性(Durabiliy)

一旦事務(wù)提交成功后,事務(wù)中所有的數(shù)據(jù)操作都必須被持久化到數(shù)據(jù)庫(kù)中滥搭,即使提交事務(wù)后酸纲,數(shù)據(jù)庫(kù)馬上崩潰,在數(shù)據(jù)庫(kù)重啟時(shí)瑟匆,也必須能保證能夠通過(guò)某種機(jī)制恢復(fù)數(shù)據(jù)闽坡。

3、事務(wù)類(lèi)型

A愁溜、自動(dòng)提交事務(wù)

系統(tǒng)默認(rèn)每個(gè)TRANSACT-SQL命令都是一個(gè)事務(wù)處理疾嗅,由系統(tǒng)自動(dòng)開(kāi)始并提交。

B冕象、隱式事務(wù)

不需要顯示開(kāi)始事務(wù)代承,需要顯示提交,隱式事務(wù)是任何單獨(dú)的INSERT渐扮、UPDATE 或者DELETE語(yǔ)句構(gòu)成论悴。當(dāng)有大量的DDL和DML命令執(zhí)行時(shí)會(huì)自動(dòng)開(kāi)始,并一直保持到用戶(hù)明確提交為止墓律。

SHOW VARIABLES 查看變量膀估。

SET AUTOCOMMIT=0,關(guān)閉自動(dòng)提交功能耻讽。

需要顯示提交或者回滾察纯。

updatetablenamesetsname='孫悟空'wherestudentid='000000000000003';

commit;

rollback;

C、顯示事務(wù)

顯示事務(wù)是用戶(hù)自定義事務(wù)齐饮,以START TRANSACTION(事務(wù)開(kāi)始)開(kāi)頭捐寥,以 COMMIT(事務(wù)提交)或者 ROLLBACK(回滾事務(wù))語(yǔ)句結(jié)束。

starttransaction

updatetablenamesetsname='孫悟空'wherestudentid='000000000000003';

commit

rollback

D祖驱、分布式事務(wù)

跨越多個(gè)服務(wù)器的事務(wù)稱(chēng)為分布式事務(wù)握恳。從MySQL5.03開(kāi)始支持分布式事務(wù)。

4捺僻、事務(wù)控制

A乡洼、開(kāi)始事務(wù)

標(biāo)記一個(gè)顯式事務(wù)的開(kāi)始點(diǎn)崇裁,即事務(wù)開(kāi)始。其語(yǔ)法如下:

START { TRAN | TRANSACTION }

B束昵、提交事務(wù)

標(biāo)記一個(gè)成功的隱性事務(wù)或顯式事務(wù)的結(jié)束拔稳,即事務(wù)提交。其語(yǔ)法如下:

COMMIT

C锹雏、回滾事務(wù)

將顯式事務(wù)或隱性事務(wù)回滾到事務(wù)的起點(diǎn)或事務(wù)內(nèi)的某個(gè)保存點(diǎn)巴比。其語(yǔ)法如下:

ROLLBACK

D、事務(wù)設(shè)置

SET AUTOCOMMIT 可以修改當(dāng)前連接事務(wù)提交方式礁遵。

SET AUTOCOMMIT=0轻绞,則需要明確的命令進(jìn)行提交或者回滾。

5佣耐、事務(wù)并發(fā)帶來(lái)的問(wèn)題

臟讀(Dirty Read)是指某個(gè)事務(wù)(A)讀取另外事務(wù)(B)尚未提交的更改數(shù)據(jù)政勃,并在讀取的數(shù)據(jù)的基礎(chǔ)上操作。如果恰巧 B事務(wù)回滾兼砖,那么 A事務(wù)讀到的數(shù)據(jù)根本是不被承認(rèn)的奸远。

不可重復(fù)讀(Unrepeatable Read)是指A事務(wù)讀取了B事務(wù)已經(jīng)提交的更改數(shù)據(jù)。

幻象讀(Phantom Read)

A事務(wù)讀取B事務(wù)提交的新增數(shù)據(jù)讽挟,這時(shí)A事務(wù)將出現(xiàn)幻象讀的問(wèn)題懒叛。

第一類(lèi)丟失更新

A事務(wù)撤銷(xiāo)時(shí),把已經(jīng)提交的B事務(wù)的更新數(shù)據(jù)覆蓋戏挡。

第二類(lèi)丟失更新

A事務(wù)覆蓋B事務(wù)已經(jīng)提交的數(shù)據(jù)芍瑞,造成B事務(wù)所做操作丟失晨仑。

二褐墅、事務(wù)隔離級(jí)別

1、事務(wù)隔離級(jí)別簡(jiǎn)介

SQL標(biāo)準(zhǔn)定義了4類(lèi)隔離級(jí)別洪己,包括了一些具體規(guī)則妥凳,用來(lái)限定事務(wù)內(nèi)外的哪些改變是可見(jiàn)的,哪些是不可見(jiàn)的答捕。低級(jí)別的隔離級(jí)一般支持更高的并發(fā)處理逝钥,并擁有更低的系統(tǒng)開(kāi)銷(xiāo)。

Read Uncommitted(讀取未提交內(nèi)容)

本隔離級(jí)別拱镐,事務(wù)可以讀取其他未提交事務(wù)的執(zhí)行結(jié)果艘款。讀取未提交的數(shù)據(jù),也被稱(chēng)之為臟讀(Dirty Read)沃琅。

Read Committed(讀取提交內(nèi)容)

大多數(shù)數(shù)據(jù)庫(kù)系統(tǒng)的默認(rèn)隔離級(jí)別(但不是MySQL默認(rèn)的)哗咆。事務(wù)只能讀取其他事務(wù)已經(jīng)提交的執(zhí)行結(jié)果。本隔離級(jí)別支持所謂的不可重復(fù)讀(Nonrepeatable Read)益眉,因?yàn)橥皇聞?wù)的其他實(shí)例在該實(shí)例處理其間可能會(huì)有新的commit晌柬,所以同一select可能返回不同結(jié)果姥份。

Repeatable Read(可重讀)

MySQL默認(rèn)的事務(wù)隔離級(jí)別,會(huì)給查詢(xún)的記錄做快照年碘,直到事務(wù)結(jié)束澈歉。確保同一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí),會(huì)看到同樣的數(shù)據(jù)行屿衅,會(huì)導(dǎo)致幻讀(Phantom Read)埃难。幻讀指當(dāng)用戶(hù)讀取某一范圍的數(shù)據(jù)行時(shí)涤久,另一個(gè)事務(wù)又在該范圍內(nèi)插入了新行凯砍,當(dāng)用戶(hù)再讀取該范圍的數(shù)據(jù)行時(shí),會(huì)發(fā)現(xiàn)有新的“幻影” 行拴竹。InnoDB和Falcon存儲(chǔ)引擎通過(guò)多版本并發(fā)控制(MVCC悟衩,Multiversion Concurrency Control)機(jī)制解決了幻讀問(wèn)題。

Serializable(可串行化)

最高的隔離級(jí)別栓拜,對(duì)同一條記錄讀和修改的多個(gè)事務(wù)只能結(jié)束一個(gè)座泳,才能開(kāi)始下一個(gè)。

通過(guò)強(qiáng)制事務(wù)排序幕与,使之不可能相互沖突挑势,從而解決幻讀問(wèn)題。在每個(gè)讀的數(shù)據(jù)行上加上共享鎖啦鸣,可能導(dǎo)致大量的超時(shí)現(xiàn)象和鎖競(jìng)爭(zhēng)潮饱。

2、事務(wù)隔離級(jí)別設(shè)置

用戶(hù)可以用SET TRANSACTION語(yǔ)句改變單個(gè)會(huì)話(huà)或者所有新進(jìn)連接的隔離級(jí)別诫给。語(yǔ)法如下:

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

默認(rèn)的行為(不帶session和global)是為下一個(gè)(未開(kāi)始)事務(wù)設(shè)置隔離級(jí)別香拉。如果使用GLOBAL關(guān)鍵字,語(yǔ)句在全局對(duì)新開(kāi)始創(chuàng)建的所有新連接設(shè)置默認(rèn)事務(wù)級(jí)別中狂,需要SUPER權(quán)限凫碌。使用SESSION關(guān)鍵字為將來(lái)在當(dāng)前連接上執(zhí)行的事務(wù)設(shè)置默認(rèn)事務(wù)級(jí)別。 任何客戶(hù)端都能自由改變會(huì)話(huà)隔離級(jí)別胃榕,或者為下一個(gè)事務(wù)設(shè)置隔離級(jí)別盛险。

查詢(xún)?nèi)趾蜁?huì)話(huà)事務(wù)隔離級(jí)別:

SELECT@@global.tx_isolation;

SELECT@@session.tx_isolation;

SELECT@@tx_isolation;

通過(guò)mySQL配置文件修改全局事務(wù)隔離級(jí)別,設(shè)置全局會(huì)話(huà)默認(rèn)事務(wù)隔離級(jí)別勋又。

[mysqld]

xxxxxxx

transaction-isolation=read-committed

重啟mySQL服務(wù)苦掘,生效。

設(shè)置當(dāng)前會(huì)隔離級(jí)別

SETSESSIONTRANSACTIONISOLATIONLEVELREADUNCOMMITTED

SETSESSIONTRANSACTIONISOLATIONLEVELREADCOMMITTED

SETSESSIONTRANSACTIONISOLATIONLEVELREPEATABLEREAD

SETSESSIONTRANSACTIONISOLATIONLEVELSERIALIZABLE

三楔壤、事務(wù)隔離級(jí)別驗(yàn)證

1鹤啡、不同會(huì)話(huà)的隔離級(jí)別

不同會(huì)話(huà)的事務(wù)隔離級(jí)別不同

在會(huì)話(huà)1終端查看當(dāng)前會(huì)話(huà)的事務(wù)隔離級(jí)別

select @@tx_isolation

查詢(xún)結(jié)果為:可重復(fù)讀REPEATABLE-READ

設(shè)置當(dāng)前會(huì)話(huà)事務(wù)隔離級(jí)別為READ UNCOMMITTED

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

打開(kāi)另一個(gè)SQL Manager終端作為會(huì)話(huà)2,查看當(dāng)前會(huì)話(huà)的事務(wù)隔離級(jí)別

select @@tx_isolation

查詢(xún)結(jié)果為:可重復(fù)讀REPEATABLE-READ

創(chuàng)建一張表挺邀,含ID揉忘、姓名跳座、年齡字段,用于驗(yàn)證不同的事務(wù)隔離級(jí)別泣矛。

CREATETABLEta

(

idINTNOTNULLPRIMARYKEY,

nameVARCHAR(10),

ageINT

)ENGINE=InnoDBDEFAULTCHARSET=utf8;

insertintotavalues(1,'孫悟空',500);

insertintotavalues(2,'唐僧',30);

注:由于本人SQL Manager Lite客戶(hù)端的事務(wù)回滾機(jī)制失效疲眷,以下實(shí)驗(yàn)使用Navicat for MySQL客戶(hù)端。

2您朽、驗(yàn)證READ UNCOMMITTED隔離級(jí)別

打開(kāi)一個(gè)會(huì)話(huà)1狂丝,設(shè)置事務(wù)隔離級(jí)別為READ UNCOMMITTED

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

打開(kāi)會(huì)話(huà)2,開(kāi)始一個(gè)事務(wù)哗总,更新ID為1的記錄的age為1000几颜。

startTRANSACTION;

updatetasetage=1000whereid=1;

在會(huì)話(huà)1查看ta表中ID為1的信息,age已經(jīng)為1000讯屈。

select * from ta;

會(huì)話(huà)1的事務(wù)隔離級(jí)別允許讀取未提交的數(shù)據(jù)蛋哭。

在會(huì)話(huà)2回滾事務(wù)

ROLLBACK;

會(huì)話(huà)1和會(huì)話(huà)2查詢(xún)ta表中ID為1的記錄,age為500

3涮母、驗(yàn)證READ COMMITTED隔離級(jí)別

打開(kāi)一個(gè)會(huì)話(huà)1谆趾,設(shè)置事務(wù)隔離級(jí)別為READ COMMITTED

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED

打開(kāi)會(huì)話(huà)2,開(kāi)始一個(gè)事務(wù)叛本,更新ID為1的記錄的age為5000沪蓬。

startTRANSACTION;

updatetasetage=5000whereid=1;

在會(huì)話(huà)1查看ta表中ID為1的信息,age為500来候。

select * from ta;

會(huì)話(huà)1的事務(wù)隔離級(jí)別不允許讀取未提交的數(shù)據(jù)跷叉。

在會(huì)話(huà)2提交事務(wù)

COMMIT;

會(huì)話(huà)1查詢(xún)ta表中ID為1的記錄,age為5000

4营搅、驗(yàn)證REPEATABLE READ隔離級(jí)別

打開(kāi)一個(gè)會(huì)話(huà)1云挟,設(shè)置事務(wù)隔離級(jí)別為REPEATABLE READ

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ

在會(huì)話(huà)1,開(kāi)始一個(gè)事務(wù)剧防,查詢(xún)ID為1的記錄的age為5000植锉。

startTRANSACTION;

SELECT*FROMtawhereid=1;

在會(huì)話(huà)2更新ta表中ID為1的信息,age為1000峭拘。

UPDATE ta SET age=1000 WHERE id=1;

在會(huì)話(huà)2查看ta表中ID為1的信息,age已經(jīng)為1000狮暑。

select * from ta WHERE id=1;

在會(huì)話(huà)1再次查看ta表中ID為1的信息鸡挠,age仍舊為5000。

select * from ta WHERE id=1;

在會(huì)話(huà)1提交事務(wù)

COMMIT;

會(huì)話(huà)1查詢(xún)ta表中ID為1的記錄搬男,age已經(jīng)為1000拣展。

5、驗(yàn)證SERIALIZABLE隔離級(jí)別

打開(kāi)一個(gè)會(huì)話(huà)1缔逛,設(shè)置事務(wù)隔離級(jí)別為SERIALIZABLE

SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE

打開(kāi)會(huì)話(huà)2备埃,開(kāi)始一個(gè)事務(wù)姓惑,更新ID為1的記錄的age為5000。

startTRANSACTION;

updatetasetage=5000whereid=1;

在會(huì)話(huà)1開(kāi)始一個(gè)事務(wù)按脚,查看ta表中ID為1的信息于毙,會(huì)話(huà)1處于等待狀態(tài)。

startTRANSACTION;

select*fromta;

在會(huì)話(huà)2提交事務(wù)后辅搬,

COMMIT;

會(huì)話(huà)1查詢(xún)SQL執(zhí)行完畢唯沮,結(jié)果為5000。

四堪遂、鎖

1介蛉、鎖簡(jiǎn)介

數(shù)據(jù)庫(kù)中的鎖是指一種軟件機(jī)制,用來(lái)控制防止某個(gè)用戶(hù)(進(jìn)程會(huì)話(huà))在已經(jīng)占用了某種數(shù)據(jù)資源時(shí)溶褪,其他用戶(hù)做出影響本用戶(hù)數(shù)據(jù)操作或?qū)е聰?shù)據(jù)非完整性和非一致性問(wèn)題發(fā)生的手段币旧。

2、鎖的級(jí)別

按照鎖級(jí)別劃分猿妈,鎖可分為共享鎖佳恬、排他鎖。

A于游、共享鎖(讀鎖)

針對(duì)同一塊數(shù)據(jù)毁葱,多個(gè)讀操作可以同時(shí)進(jìn)行而不會(huì)互相影響。

共享鎖只針對(duì)UPDATE時(shí)候加鎖贰剥,在未對(duì)UPDATE操作提交之前倾剿,其他事務(wù)只能夠獲取最新的記錄但不能夠UPDATE操作。

B蚌成、排他鎖(寫(xiě)鎖)

當(dāng)前寫(xiě)操作沒(méi)有完成前前痘,阻斷其他寫(xiě)鎖和讀鎖。

3担忧、鎖的粒度

按鎖的粒度劃分芹缔,鎖可分為表級(jí)鎖、行級(jí)鎖瓶盛、頁(yè)級(jí)鎖最欠。

A、行級(jí)鎖

開(kāi)銷(xiāo)大惩猫,加鎖慢芝硬,會(huì)出現(xiàn)死鎖,鎖定力度最小轧房,發(fā)生鎖沖突的概率最低拌阴,并發(fā)度高。

B奶镶、表級(jí)鎖

開(kāi)銷(xiāo)小迟赃,加鎖快陪拘,不會(huì)出現(xiàn)死鎖,鎖定力度大纤壁,發(fā)生沖突所的概率高左刽,并發(fā)度低。

C摄乒、頁(yè)面鎖

開(kāi)銷(xiāo)和加鎖時(shí)間介于表鎖和行鎖之間悠反,會(huì)出現(xiàn)死鎖,鎖定力度介于表和行行級(jí)鎖之間馍佑,并發(fā)度一般斋否。

4、MySQL存儲(chǔ)引擎和鎖機(jī)制

MySQL的鎖機(jī)制比較簡(jiǎn)單拭荤,最顯著的特點(diǎn)是不同的存儲(chǔ)引擎支持不同的鎖機(jī)制茵臭。

MyISAM和MEMORY存儲(chǔ)引擎采用表級(jí)鎖。

InnoDB支持行級(jí)鎖舅世、表級(jí)鎖旦委,默認(rèn)情況采用行級(jí)鎖。

五雏亚、表級(jí)鎖

1缨硝、表級(jí)鎖簡(jiǎn)介

MyISAM存儲(chǔ)引擎和InnoDB存儲(chǔ)引擎都支持表級(jí)鎖。

MyISAM存儲(chǔ)引擎支持表級(jí)鎖罢低,為了保證數(shù)據(jù)的一致性查辩,更改數(shù)據(jù)時(shí),防止其他人更改數(shù)據(jù)网持,可以人工添加表級(jí)鎖宜岛。可以使用命令對(duì)數(shù)據(jù)庫(kù)的表枷鎖功舀,使用命令對(duì)數(shù)據(jù)庫(kù)的表解鎖萍倡。

給表加鎖的命令Lock Tables,給表解鎖的命令Unlock Tables

MyISAM引擎在用戶(hù)讀數(shù)據(jù)自動(dòng)加READ鎖辟汰,更改數(shù)據(jù)自動(dòng)加WRITE鎖列敲。使用lock Tables和Unlock Tables顯式加鎖和解鎖。

2莉擒、添加表級(jí)讀鎖

打開(kāi)會(huì)話(huà)1酿炸,創(chuàng)建表

CREATETABLEtc

(

idINT,

nameVARCHAR(10),

ageINT

)ENGINE=MyISAMDEFAULTCHARSET=utf8;

插入兩條記錄:

insertintotcvalues(1,'孫悟空',500);

insertintotcvalues(3,'豬八戒',100);

對(duì)表加READ鎖

lock tables tc read;

加鎖后只可以查詢(xún)已經(jīng)加鎖的表,

select * from tc;

查詢(xún)沒(méi)有加鎖的表將失敗

select * from ta;

打開(kāi)會(huì)話(huà)2涨冀,對(duì)已經(jīng)加鎖的表進(jìn)行查詢(xún),成功麦萤。

select * from tc;

對(duì)加鎖的表tc進(jìn)行更新操作鹿鳖,將失敗

update tc set age=100 where id=1;

會(huì)話(huà)1中使用LOCK TABLE命令給表加了讀鎖扁眯,會(huì)話(huà)1可以查詢(xún)鎖定表中的記錄,但更新或訪問(wèn)其他表都會(huì)提示錯(cuò)誤翅帜;會(huì)話(huà)2可以查詢(xún)表中的記錄姻檀,但更新就會(huì)出現(xiàn)鎖等待。

在會(huì)話(huà)1對(duì)表進(jìn)行解鎖涝滴,會(huì)話(huà)2的更新操作成功绣版。

unlock tables;

在會(huì)話(huà)1,再次鎖定表tc歼疮,后面帶local參數(shù)杂抽。

lock tables tc read local;

Local參數(shù)允許在表尾并發(fā)插入,只鎖定表中當(dāng)前記錄韩脏,其他會(huì)話(huà)可以插入新的記錄

在會(huì)話(huà)2插入一條記錄

insert into tc values(2, '唐僧', 20);

在會(huì)話(huà)1查看tc表的記錄缩麸,無(wú)插入記錄

select * from tc;

3、設(shè)置表級(jí)鎖并發(fā)性

READ鎖是共享鎖赡矢,不影響其他會(huì)話(huà)的讀取杭朱,但不能更新已經(jīng)加READ鎖的數(shù)據(jù)。MyISAM表的讀寫(xiě)是串行的吹散,但是總體而言的弧械,在一定條件下,MyISAM表也支持查詢(xún)和插入操作的并發(fā)進(jìn)行空民。

MyISAM存儲(chǔ)引擎有一個(gè)系統(tǒng)變量concurrent_insert刃唐,用以控制其并發(fā)插入的行為,其值分別可以為0袭景、1或2唁桩。

0:不允許并發(fā)操作

1:如果MyISAM表中沒(méi)有空洞(即表的中間沒(méi)有被刪除的行),MyISAM允許在一個(gè)進(jìn)程讀表的同時(shí)耸棒,另一個(gè)進(jìn)程從表尾插入記錄荒澡,是MySQL的默認(rèn)設(shè)置。

2:無(wú)論MyISAM表中有沒(méi)有空洞与殃,都允許在表尾并發(fā)插入記錄单山。

在MySQL配置文件添加,concurrent_insert=2幅疼,重啟mySQL服務(wù)設(shè)置生效米奸。

4、驗(yàn)證表級(jí)鎖的并發(fā)性

設(shè)置concurrent_insert為0

在會(huì)話(huà)1對(duì)表tc加鎖

lock tables tc read local;

在會(huì)話(huà)2插入一條記錄爽篷,此時(shí)tc表被鎖定悴晰,進(jìn)入等待

insert into tc values(4, '沙悟凈', 30);

在會(huì)話(huà)1解鎖表tc,此時(shí)會(huì)話(huà)2插入成功

unlock tables;

設(shè)置concurrent_insert為1

在會(huì)話(huà)1刪除ID為3的記錄

delete from tc where id=3;

在會(huì)話(huà)1對(duì)表tc加鎖

lock tables tc read local;

在會(huì)話(huà)2插入一條記錄,此時(shí)tc表被鎖定铡溪,并且表中有空洞漂辐,進(jìn)入等待

insert into tc values(5, '白骨精', 1000);

在會(huì)話(huà)1解鎖表tc,此時(shí)會(huì)話(huà)2插入成功棕硫,此時(shí)表中已經(jīng)沒(méi)有空洞

unlock tables;

在會(huì)話(huà)1對(duì)表tc加鎖

lock tables tc read local;

在會(huì)話(huà)2插入一條記錄髓涯,插入成功,支持有條件并發(fā)插入

insert into tc values(6, '白骨精', 1000);

在會(huì)話(huà)1解鎖表tc

unlock tables;

設(shè)置concurrent_insert為2

在會(huì)話(huà)1刪除ID為5的記錄哈扮,創(chuàng)造一個(gè)空洞

delete from tc where id=5;

在會(huì)話(huà)1對(duì)表tc加鎖

lock tables tc read local;

在會(huì)話(huà)2插入一條記錄纬纪,插入成功,支持無(wú)條件并發(fā)插入

insert into tc values(7, '蜘蛛精', 1000);

在會(huì)話(huà)1解鎖表tc

unlock tables;

5滑肉、添加表級(jí)寫(xiě)鎖

添加表級(jí)寫(xiě)鎖語(yǔ)法如下:

LOCK TABLES tablename WRITE;

不允許其他會(huì)話(huà)查詢(xún)包各、修改、插入記錄赦邻。

六髓棋、行級(jí)鎖

1、行級(jí)鎖簡(jiǎn)介

InnoDB存儲(chǔ)引擎實(shí)現(xiàn)的是基于多版本的并發(fā)控制協(xié)議——MVCC (Multi-Version Concurrency Control)惶洲。MVCC的優(yōu)點(diǎn)是讀不加鎖按声,讀寫(xiě)不沖突。在讀多寫(xiě)少的OLTP應(yīng)用中恬吕,讀寫(xiě)不沖突是非常重要的签则,極大的增加了系統(tǒng)的并發(fā)性能。

在MVCC并發(fā)控制中铐料,讀操作可以分成兩類(lèi):快照讀 (snapshot read)與當(dāng)前讀 (current read)渐裂。

快照讀,讀取的是記錄的可見(jiàn)版本 (有可能是歷史版本)钠惩,不用加鎖柒凉。

當(dāng)前讀,讀取的是記錄的最新版本篓跛,并且當(dāng)前讀返回的記錄都會(huì)加上鎖膝捞,保證其他事務(wù)不會(huì)再并發(fā)修改。事務(wù)加鎖愧沟,是針對(duì)所操作的行蔬咬,對(duì)其他行不進(jìn)行加鎖處理。

快照讀:簡(jiǎn)單的SELECT操作沐寺,屬于快照讀林艘,不加鎖。

select * from table where ?;

當(dāng)前讀:特殊的讀操作混坞,INSERT/UPDATE/DELETE狐援,屬于當(dāng)前讀,需要加鎖。

select*fromtablewhere?lockinsharemode;

select*fromtablewhere?forupdate;

insertintotablevalues(…);

updatetableset?where?;

deletefromtablewhere?;

以上SQL語(yǔ)句屬于當(dāng)前讀咕村,讀取記錄的最新版本场钉。并且蚊俺,讀取之后懈涛,還需要保證其他并發(fā)事務(wù)不能修改當(dāng)前記錄,對(duì)讀取記錄加鎖泳猬。其中批钠,除了第一條語(yǔ)句,對(duì)讀取記錄加S鎖 (共享鎖)外得封,其他的操作埋心,都加的是X鎖 (排它鎖)。

2忙上、驗(yàn)證快照讀

打開(kāi)會(huì)話(huà)1拷呆,創(chuàng)建一個(gè)表,含ID疫粥、姓名茬斧、年齡

CREATETABLEtd

(

idINT,

nameVARCHAR(10),

ageINT

)ENGINE=innoDBDEFAULTCHARSET=utf8;

在插入兩條記錄

insertintotdvalues(1,'孫悟空',500);

insertintotdvalues(2,'豬八戒',100);

在會(huì)話(huà)1開(kāi)始事務(wù)

start transaction;

在會(huì)話(huà)1查詢(xún)ID位1的記錄信息

select * from td where id =1;

打開(kāi)會(huì)話(huà)2,更新ID為1的age為1000

update td set age=1000 where id=1;

在會(huì)話(huà)2查看ID為1的age已經(jīng)更新為1000梗逮。

select * from td where id =1;

在會(huì)話(huà)1查看ID為1的age项秉,仍然為500。

select * from td where id =1;

在會(huì)話(huà)1提交事務(wù)

COMMIT;

在會(huì)話(huà)1查看ID為1的age慷彤,已經(jīng)為1000娄蔼。

3、驗(yàn)證當(dāng)前讀

在會(huì)話(huà)1開(kāi)始事務(wù)

start transaction;

在會(huì)話(huà)1給select語(yǔ)句添加共享鎖底哗。

select * from td where id=1 lock in share mode;

在會(huì)話(huà)2岁诉,更新ID為1的age的值為100,進(jìn)入鎖等待

update td set age=100 where id=1;

在會(huì)話(huà)1提交事務(wù)

COMMIT;

會(huì)話(huà)2的更新操作成功跋选。

4涕癣、驗(yàn)證事務(wù)給記錄加鎖

在會(huì)話(huà)1開(kāi)始事務(wù)

start transaction;

在會(huì)話(huà)1更新ID為1的age的值為500。

update td set age=500 where id=1;

在會(huì)話(huà)2開(kāi)始事務(wù)

start transaction;

在會(huì)話(huà)2更新ID為2的age的值為1000野建,此時(shí)進(jìn)入鎖等待

update td set age=1000 where id=2;

td表沒(méi)有指定主鍵属划,事務(wù)不支持行級(jí)鎖。會(huì)話(huà)1的事務(wù)給整張表加了鎖候生。

在會(huì)話(huà)1提交事務(wù)同眯,此時(shí)會(huì)話(huà)2的修改成功

COMMIT;

在會(huì)話(huà)2提交事務(wù),解除對(duì)表的鎖定

COMMIT;

在會(huì)話(huà)1唯鸭,給表的ID增加主鍵

alter table td add primary key(id);

在會(huì)話(huà)1開(kāi)始事務(wù)

start transaction;

在會(huì)話(huà)1更新ID為1的age的值為5000

update td set age=5000 where id=1;

在會(huì)話(huà)2上開(kāi)始事務(wù)

start transaction;

在會(huì)話(huà)2上修改ID為2的get的值為10000须蜗,更新成功,說(shuō)明會(huì)話(huà)1只鎖定了ID為1的行。

update td set age=10000 where id=2;

在會(huì)話(huà)2上更新ID是1的age值為100明肮,出現(xiàn)等待菱农。因?yàn)闀?huì)話(huà)1給ID為1的行添加了獨(dú)占鎖。

update td set age=5000 where id=1;

在會(huì)話(huà)1提交事務(wù)

COMMIT;

在會(huì)話(huà)2提交事務(wù)

COMMIT;

在會(huì)話(huà)1查詢(xún)柿估,會(huì)話(huà)1和會(huì)話(huà)2對(duì)age列的修改都生效

select * from td;

5循未、死鎖的產(chǎn)生

A事務(wù)添加共享鎖后,B事務(wù)也可以添加共享鎖秫舌。A事務(wù)UPDATE鎖定記錄的妖,處于等待中,于此同時(shí)B事務(wù)也UPDATE更新鎖定的記錄足陨,就產(chǎn)生死鎖嫂粟。

在會(huì)話(huà)1開(kāi)始事務(wù)

start transaction;

在會(huì)話(huà)1查詢(xún)ID是1的記錄,并添加共享鎖墨缘。

select * from td where id=1 lock in share mode;

在會(huì)話(huà)2開(kāi)始事務(wù)

start transaction;

在會(huì)話(huà)2查詢(xún)ID是1的記錄星虹,并添加共享鎖。

select * from td where id=1 lock in share mode;

在會(huì)話(huà)1更新ID為1的age值為镊讼,等待會(huì)話(huà)2釋放共享鎖

update td set age=200 where id=1;

在會(huì)話(huà)2更新ID為1的age為宽涌,會(huì)話(huà)2發(fā)現(xiàn)死鎖,回滾事務(wù)狠毯。

update td set age=200 where id=1;

在會(huì)話(huà)1提交事務(wù)

COMMIT;

七护糖、事務(wù)實(shí)例

事務(wù)提交還是回滾,可以在事務(wù)結(jié)束處判斷是否出現(xiàn)錯(cuò)誤嚼松,如果出現(xiàn)嫡良,回滾。如果沒(méi)有錯(cuò)誤献酗,提交事務(wù)寝受。

使用自定義條件來(lái)決定事務(wù)是提交還是回滾。

1罕偎、由錯(cuò)誤決定事務(wù)提交或回滾

在存儲(chǔ)過(guò)程中使用事務(wù)很澄,在事務(wù)的末尾判斷是否有錯(cuò)誤,插入失敗颜及,則回滾事務(wù)甩苛。

創(chuàng)建兩張表,存儲(chǔ)ID俏站、姓名讯蒲、年齡,創(chuàng)建存儲(chǔ)過(guò)程將A表的指定ID的記錄轉(zhuǎn)移到B表肄扎。

CREATETABLEta

(

idINTNOTNULLPRIMARYKEY,

nameVARCHAR(10),

ageINT

)ENGINE=InnoDBDEFAULTCHARSET=utf8;

insertintotavalues(1,'孫悟空',500);

insertintotavalues(2,'唐僧',30);

CREATETABLEtb

(

idINTNOTNULLPRIMARYKEY,

nameVARCHAR(10),

ageINT

)ENGINE=InnoDBDEFAULTCHARSET=utf8;

insertintotbvalues(1,'孫悟空',500);

insertintotbvalues(3,'豬八戒',100);

CREATEPROCEDUREmove(numINT)

BEGIN

DECLAREerrorinfoINTDEFAULT0;

DECLARECONTINUEHANDLERFORSQLEXCEPTIONSETerrorinfo=1;

STARTTRANSACTION;

INSERTINTOtbSELECT*FROMtaWHEREid=num;

DELETEFROMtaWHEREid=num;

IF errorinfo=1

THENROLLBACK;

ELSE

COMMIT;

ENDIF;

END

將ID為2的記錄從A表轉(zhuǎn)移到B表

call move(2);

2墨林、由自定義條件決定事務(wù)提交或回滾

創(chuàng)建兩個(gè)表赁酝,每個(gè)表含賬戶(hù)、姓名旭等、余額信息酌呆,創(chuàng)建一個(gè)存儲(chǔ)過(guò)程,從A表中的一個(gè)賬戶(hù)轉(zhuǎn)賬一定金額到B表的一個(gè)賬戶(hù)搔耕,如果轉(zhuǎn)出賬戶(hù)的余額不足隙袁,則回滾,否則提交度迂。

create table accountA

(

account INT PRIMARYKEYNOTNULL,

name VARCHAR(10),

balanceDOUBLE

)ENGINE=innoDBdefaultCHARSET=utf8;

insertintoaccountA VALUES(1,'孫悟空', 10000);

insertintoaccountA VALUES(2,'唐僧', 20000);

create table accountB

(

account INT PRIMARYKEYNOTNULL,

name VARCHAR(10),

balanceDOUBLE

)ENGINE=innoDBdefaultCHARSET=utf8;

insertintoaccountB VALUES(1,'孫悟空', 10000);

insertintoaccountB VALUES(2,'唐僧', 20000);

CREATE PROCEDURE transfer(fromaccout INT,toaccount INT, numDOUBLE)

BEGIN

DECLAREmDOUBLE;

START TRANSACTION;

UPDATE accountBSETbalance=balance + numWHEREaccount=toaccount;

UPDATE accountASETbalance=balance - numWHEREaccount=fromaccout;

SELECTbalanceINTOmfromaccountAWHEREaccount=fromaccout;

IFm <0

THENROLLBACK;

ELSE

? COMMIT;

ENDIF;

END

從A表的賬戶(hù)2轉(zhuǎn)出25000元到B表的賬戶(hù)2藤乙。

call transfer(2,2,25000);

此時(shí)A表的余額不足,回滾

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惭墓,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子而姐,更是在濱河造成了極大的恐慌腊凶,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拴念,死亡現(xiàn)場(chǎng)離奇詭異钧萍,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)政鼠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)风瘦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人公般,你說(shuō)我怎么就攤上這事万搔。” “怎么了官帘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵瞬雹,是天一觀的道長(zhǎng)磺平。 經(jīng)常有香客問(wèn)我昌讲,道長(zhǎng),這世上最難降的妖魔是什么利诺? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任涌哲,我火速辦了婚禮胖缤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘阀圾。我一直安慰自己哪廓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布稍刀。 她就那樣靜靜地躺著撩独,像睡著了一般敞曹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上综膀,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天澳迫,我揣著相機(jī)與錄音,去河邊找鬼剧劝。 笑死橄登,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的讥此。 我是一名探鬼主播拢锹,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼萄喳!你這毒婦竟也來(lái)了卒稳?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤他巨,失蹤者是張志新(化名)和其女友劉穎充坑,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體染突,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捻爷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了份企。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片也榄。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖司志,靈堂內(nèi)的尸體忽然破棺而出甜紫,到底是詐尸還是另有隱情,我是刑警寧澤俐芯,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布棵介,位于F島的核電站,受9級(jí)特大地震影響吧史,放射性物質(zhì)發(fā)生泄漏邮辽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一贸营、第九天 我趴在偏房一處隱蔽的房頂上張望吨述。 院中可真熱鬧,春花似錦钞脂、人聲如沸揣云。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)邓夕。三九已至刘莹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間焚刚,已是汗流浹背点弯。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留矿咕,地道東北人抢肛。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像碳柱,于是被迫代替她去往敵國(guó)和親捡絮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容