本文內(nèi)容很多來(lái)自教材《Mysql 數(shù)據(jù)庫(kù)技術(shù)與應(yīng)用(慕課版)》,感謝作者寫出了這么優(yōu)秀的教材。
一.什么事務(wù)
事務(wù)是單個(gè)工作單元,是數(shù)據(jù)庫(kù)中不可再分的基本部分.具體來(lái)說(shuō),事務(wù)是由用戶定義的一個(gè)sql語(yǔ)句序列,在這組sql序列中,每個(gè)mysql語(yǔ)句時(shí)相互依賴的,整個(gè)sql語(yǔ)句組是一個(gè)不可分割的整體.如果在這個(gè)sql語(yǔ)句組某條sql語(yǔ)句一旦執(zhí)行失敗或產(chǎn)生錯(cuò)誤,整個(gè)語(yǔ)句將會(huì)回滾,即將數(shù)據(jù)表中的數(shù)據(jù)返回到這個(gè)sql語(yǔ)句組開始執(zhí)行前的狀態(tài).
mysql查看事務(wù)自動(dòng)提交 為true or false
show variables like 'autocommit'
關(guān)閉自動(dòng)提交模式
set autocommit = 0
begin;
執(zhí)行語(yǔ)句一
執(zhí)行語(yǔ)句二
commit;
未提交可以用 rollback; 回滾
二.事務(wù)的4個(gè)屬性ACID
1.原子性(Atomicity):事務(wù)由一個(gè)或一組相互關(guān)聯(lián)的sql語(yǔ)句組成, 這些語(yǔ)句被認(rèn)為是一個(gè)不可分割的單元,對(duì)事務(wù)進(jìn)行修改只能是完全提交或完全回滾
????????簡(jiǎn)單說(shuō):要執(zhí)行都執(zhí)行,不執(zhí)行則都不執(zhí)行。
2.一致性(Consistency):事務(wù)的一致性保含兩層意思: 一是從數(shù)據(jù)的角度來(lái)看,事務(wù)必須是使數(shù)據(jù)庫(kù)從一個(gè)一致性變?yōu)榱硪粋€(gè)一致性,一致性與原子性密切相關(guān),在事務(wù)開始之前和結(jié)束之后,數(shù)據(jù)庫(kù)的完整性約束沒有被破壞;而是從用戶的角度看,事務(wù)可確保對(duì)數(shù)據(jù)庫(kù)修改是一致的,即多個(gè)用戶查詢到的數(shù)是一樣的.
????????我理解:一致性就是 從上面的文字理解:從業(yè)務(wù)角度看 ,一個(gè)事務(wù)發(fā)生后,無(wú)論對(duì)于多個(gè)客戶和還是一個(gè)客戶,無(wú)論哪個(gè)事件段,數(shù)據(jù)數(shù)據(jù)狀態(tài)都不會(huì)變化
3.隔離性(Isolation,孤立性):一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)干擾,即一個(gè)事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)對(duì)并發(fā)的其他事務(wù)是隔離的,并發(fā)執(zhí)行的各個(gè)事務(wù)之間不應(yīng)該相互干擾,這些通過鎖來(lái)實(shí)現(xiàn).實(shí)際應(yīng)用中,事務(wù)的相互影響程度受到隔離級(jí)別的影響.
????????隔離性是對(duì)多個(gè)事務(wù)操作同一組數(shù)據(jù)時(shí), 相互不影響彼此,最終數(shù)據(jù)結(jié)果符和邏輯。
4.持久性(Durability):指一個(gè)事務(wù)一旦提交后,對(duì)數(shù)據(jù)的修改和更新及時(shí)永久的.
????????事務(wù)成功后,數(shù)據(jù)形態(tài)及狀態(tài)永久性發(fā)生變化, 直到下次事務(wù)發(fā)生。
三.事務(wù)的控制
start transaction| begin 用于開啟一個(gè)事務(wù)
commit 表示提交一個(gè)事務(wù)
rollback 表示回滾一個(gè)事務(wù)
set autocommit = {0|1}表示用于設(shè)置提交事務(wù)的默認(rèn)方式,0 表示禁用自動(dòng)提交事務(wù), 1 表示自動(dòng)提交事務(wù).and chain 表示會(huì)在當(dāng)前事務(wù)結(jié)束時(shí)立刻啟動(dòng)一個(gè)新的事務(wù),并且新事務(wù)與剛結(jié)束的事務(wù)有相同的隔離等級(jí); release 表示在終止了當(dāng)前事務(wù)后,會(huì)讓服務(wù)器斷開與當(dāng)前客戶端的連接.如果加上 no,則可以抑制chain 和release的完成.
四.事務(wù)的隔離級(jí)別
臟讀(DIrty Read): 一個(gè)事務(wù)讀取到了另一個(gè)事務(wù)未提交的的數(shù)據(jù)操作結(jié)果.你修改了數(shù)據(jù),但沒有提交,數(shù)據(jù)結(jié)果可能就不準(zhǔn)確了。我卻讀到了你修改后的臟數(shù)據(jù)。不可重復(fù)讀(Non-repeatable Reads):一個(gè)事務(wù)對(duì)同一行重復(fù)數(shù)據(jù)重復(fù)讀兩次,但卻得到了不同的結(jié)果,即產(chǎn)生了虛讀,也就是當(dāng)事務(wù)讀取某一數(shù)據(jù)后, 事務(wù)二對(duì)其做了修改,當(dāng)事務(wù)再次讀該數(shù)據(jù)時(shí)得到與第一次不同的值.
? ? ? ? 用我理解的話說(shuō):我讀了兩次, 第一次讀和第二次讀 的結(jié)果不一樣,重復(fù)度的結(jié)果不一樣
幻讀(Phantom Reads):指事務(wù)在操作過程中進(jìn)行兩次查詢,第二次查詢的結(jié)果包含了第一次查詢中未出現(xiàn)的數(shù)據(jù)或者缺少了第一次查詢中出現(xiàn)的數(shù)據(jù),這是由于在兩次查詢過程中有另外一個(gè)事務(wù)更新了數(shù)據(jù)造成的.
? ? ? ? 用我的話說(shuō):我第一次讀到了三條數(shù)據(jù),第二次讀到兩條,讓我產(chǎn)生了幻覺。
為了避免上述3種情況的發(fā)生,mysql 定義的了不同的隔離級(jí)別,以此來(lái)保證數(shù)據(jù)的穩(wěn)定性。
1.讀未提交(Read Uncommitted)
允許事務(wù)讀取其他事務(wù)未提交的結(jié)果,是事務(wù)隔離級(jí)別中等級(jí)最低的,能容忍臟數(shù)據(jù)被讀到。
2.讀已提交(Read Committed)
允許事務(wù)讀取其他事務(wù)已經(jīng)提交的結(jié)果,該隔離級(jí)別可以避免臟讀,但不能避免不可重復(fù)讀和幻讀的情況。
3.可重復(fù)度(Repeatable Read)
這是Mysql的默認(rèn)事務(wù)隔離級(jí)別,它確保同一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí)會(huì)看到同樣的數(shù)據(jù)行.可以避免臟讀和幻讀,不能避免幻讀。是MySql默認(rèn)的隔離級(jí)別
4.可串行化(Serializable)
這是最高的隔離級(jí)別,它通過強(qiáng)制事務(wù)排序,使事務(wù)只能一個(gè)接一個(gè)執(zhí)行,不能并發(fā)執(zhí)行,這樣就從根本上阻止了事務(wù)之間的相互沖突,從而解決幻讀問題.
查詢當(dāng)前會(huì)話的隔離級(jí)別
select @@tx_isolation
修改事務(wù)隔離級(jí)別的語(yǔ)法規(guī)則:
set[Global|session]Transation isolation level read uncommitted | Read committed | Repeatable read|Serializable ;
Global 表示此語(yǔ)句將應(yīng)用于在此之后所有session,而當(dāng)前已經(jīng)存在的session不受影響."session"表示此語(yǔ)句將應(yīng)用于在此之后所有session之內(nèi)的以及之后的所有事務(wù);session表示此語(yǔ)句將應(yīng)用于包括當(dāng)前session在內(nèi)的及其后的所有事務(wù);如果缺省.表示此語(yǔ)句將應(yīng)用于當(dāng)前session在內(nèi)的后面未開始事務(wù)."Read uncommitted | Read committed | Repeatable read | Serializable"分別表示設(shè)置為讀未提交/讀以提交,可重復(fù)讀 和可串行化.
隔離級(jí)別的選取
事務(wù)的隔離級(jí)別越高越能保證數(shù)據(jù)的完整性和一致性,但是對(duì)系統(tǒng)并發(fā)性能的影響越大。在選取數(shù)據(jù)庫(kù)的隔離級(jí)別時(shí),可以參照以下幾個(gè)原則:
1.首先,需要排除數(shù)據(jù)臟讀的影響,在多個(gè)事務(wù)之間要避免進(jìn)行”非授權(quán)的讀“操作。因?yàn)槭聞?wù)的回滾操作或失敗將會(huì)影響其他的并發(fā)事務(wù),第一個(gè)事務(wù)的回滾會(huì)完全將其他事務(wù)的操作清楚,這可能導(dǎo)致數(shù)據(jù)處于一個(gè)不一致的狀態(tài)。
2.其次,數(shù)據(jù)的幻讀可以通過使用悲觀鎖這種強(qiáng)行使所有事務(wù)都序列化執(zhí)行的方式來(lái)解決。
3.對(duì)于大部分應(yīng)用,可以優(yōu)先考慮可重復(fù)讀。
五.并發(fā)與并行
并發(fā)控制是 把時(shí)間分成若干的段。讓多個(gè)線程快速交替輪換執(zhí)行,使得在宏觀上具有多個(gè)線程同時(shí)執(zhí)行效果控制方法。
并行指的是同一時(shí)刻有多條指令在多個(gè)cpu上同時(shí)執(zhí)行,無(wú)論從微觀上還是宏觀上來(lái)看,多個(gè)線程都是同時(shí)執(zhí)行的。
六 鎖機(jī)制:
mysql 中多種存儲(chǔ)引擎,不同的存儲(chǔ)引擎的鎖機(jī)制之間本質(zhì)上存在較大的區(qū)別。mysql 中常見的InnoDB 引擎 支持行級(jí)鎖,但有時(shí)也會(huì)升級(jí)為表級(jí)鎖,而MyISAM 引擎只支持表級(jí)鎖。
表級(jí)鎖的特點(diǎn)是開銷小,加鎖快,不會(huì)出現(xiàn)死鎖。由于鎖粒度大,發(fā)生鎖沖突的概率較高,抗并發(fā)能力較低。
行級(jí)鎖的特點(diǎn)是開銷大,加鎖慢,會(huì)出現(xiàn)死鎖的情況。由于鎖粒度小,發(fā)生鎖沖突概率較低,抗并發(fā)能力較高。
實(shí)際上,各種隔離級(jí)別也是靠鎖機(jī)制實(shí)現(xiàn)的。
InnoDB 鎖類型
數(shù)據(jù)庫(kù)系統(tǒng)中常見的鎖粒度可以劃分為表級(jí)鎖,行級(jí)鎖和頁(yè)級(jí)鎖,行級(jí)鎖中主要的鎖類型有讀鎖,寫鎖,而表級(jí)鎖的鎖有意向鎖。
1.讀鎖
讀鎖又被稱為共享鎖(Shared Locks ,簡(jiǎn)稱為S)。S鎖的粒度是行級(jí)或元組級(jí)(多個(gè)行),多個(gè)不同的事務(wù)對(duì)一個(gè)資源共享一把鎖。如果事務(wù)T1 對(duì)行R 加上S鎖,會(huì)產(chǎn)生以下情況。
1.其他事務(wù)T2 T3 ......Tn 只能對(duì)行R加上S鎖, 不能再加上其他的鎖。
2.被加上S鎖的數(shù)據(jù),用戶只能進(jìn)行讀取,不能寫入數(shù)據(jù)(包括修改和刪除)
3.如果需要修改數(shù)據(jù),必須等所有的共享鎖釋放完。
Mysql 中共享鎖的語(yǔ)法格式如下:
SELECT * FROM 表名 where 條件 Lock in share mode;
2.寫鎖
寫鎖又被稱為排它鎖(Exclusive Locks ,簡(jiǎn)稱為X) X鎖也是作用于行或者元組的。如果一個(gè)事務(wù)T1對(duì)行R加上X鎖,會(huì)產(chǎn)生以下情況。
1.事務(wù)T1 可以 對(duì)行R 范圍內(nèi)的數(shù)據(jù)進(jìn)行讀取和寫入操作(包括修改和刪除)。
2.其他事務(wù)都不能對(duì)于R施加任何類型的鎖,而且無(wú)法進(jìn)行增刪改操作,直到事務(wù)T1在行R上的X鎖被釋放。
Mysql 中設(shè)置X鎖的語(yǔ)法格式如下。
SELECT * FROM 表名 where 條件 for update;
排它鎖指的是一個(gè)事務(wù)為一行數(shù)據(jù)加上排它鎖后,其他事務(wù)不能再在其上加其他鎖。MySql 的InnoDB 引擎默認(rèn)的修改語(yǔ)句update , delete, insert? 都會(huì)自動(dòng)給涉及的數(shù)據(jù)加上排它鎖,select 語(yǔ)句默認(rèn)不會(huì)加上任何鎖。
3.意向鎖
在InnoDB 引擎中 ,意向鎖 的粒度 為表級(jí)。意向鎖是數(shù)據(jù)庫(kù)自身行為,不需要人工干預(yù),在事務(wù)結(jié)束后會(huì)自行解除。意向鎖分為意向共享鎖IS, 和意向排它鎖IX , 其主要作用是提升存儲(chǔ)引擎的的性能。
? 在InnoDB 引擎中的S鎖 和X鎖為 行級(jí)鎖,每當(dāng)事務(wù)到來(lái)時(shí),存儲(chǔ)引擎需要遍歷所有行的鎖持有情況,這樣會(huì)增加系統(tǒng)的性能損耗。因此Mysql 數(shù)據(jù)庫(kù)系統(tǒng)引入了意向鎖,在檢查行級(jí)鎖之前會(huì)先檢查意向鎖是否存在,如果存在則阻塞線程。
4.間隙鎖
間隙鎖是InnoDB 引擎在可重復(fù)讀 的隔離級(jí)別下為了解決幻讀和數(shù)據(jù)誤刪問題而引入的鎖機(jī)制。
5.鎖等待和死鎖
鎖等待是指在一個(gè)事務(wù)執(zhí)行過程中,一個(gè)鎖需要等上一個(gè)事務(wù)鎖釋放后才能可以使用該資源。如果事務(wù)一直不釋放,就需要持續(xù)等待下去,直到超過鎖等待時(shí)間,此時(shí)系統(tǒng)會(huì)報(bào)出超時(shí)錯(cuò)誤。
Mysql 中鎖等待時(shí)間是通過 innodb_lock_wait_timeout 參數(shù)控制。
查看鎖等待時(shí)間
show variables like '%innodb_lock_wait%';
鎖的鎖監(jiān)控 與 優(yōu)化
Mysql 中可以通過 SHOW FULL PROCESSLIST 命令和 SHOW ENGINE INNODB STATUS 命令來(lái)監(jiān)控 事務(wù)中鎖的情況。也可以通過查詢 inormation schema 庫(kù)下的INNODB TRX? INNODB LOCKS 和INNODB LOCK WAITS 這三張表 來(lái)獲取更加詳細(xì)的信息。
在使用InnoDB 引擎時(shí), 應(yīng)該注意以下幾點(diǎn)
1.合理設(shè)置索引, 盡可能 讓所有數(shù)據(jù) 檢索都通過 索引來(lái)完成,從而避免InnoDB 引擎因?yàn)闊o(wú)法通過索引枷鎖 而升級(jí) 為表級(jí)鎖定的現(xiàn)象。
2.減少基于范圍的數(shù)據(jù)檢索,避免因間隙鎖帶來(lái)的負(fù)面影響而鎖定了不該鎖定的記錄。
3.控制事務(wù)的大小,縮減鎖定的資源量和鎖定時(shí)間。
4.在業(yè)務(wù)允許的情況下,盡量使用較低級(jí)別的事務(wù)隔離,以減少M(fèi)ySql 實(shí)現(xiàn)事務(wù)隔離級(jí)別的附加成本。
在同一個(gè)事務(wù)中,盡可能做到一次性鎖定需要的所有資源,降低死鎖發(fā)生的概率。