事務(wù)的四個(gè)特征(ACID)
- 原子性(atomicity):一個(gè)事務(wù)必須視為一個(gè)不可分割的最小工作單元,整個(gè)事務(wù)中的所有操作要么全部提交成功,要么全部失敗回滾,對(duì)于一個(gè)事務(wù)來(lái)說(shuō),不可能只執(zhí)行其中的一部分操作,這就是事務(wù)的原子性。
- 一致性(consistency):數(shù)據(jù)庫(kù)總數(shù)從一個(gè)一致性的狀態(tài)轉(zhuǎn)換到另一個(gè)一致性的狀態(tài)。
- 隔離性(isolation):一個(gè)事務(wù)所做的修改在最終提交以前,對(duì)其他事務(wù)是不可見(jiàn)的。
- 持久性(durability):一旦事務(wù)提交,則其所做的修改就會(huì)永久保存到數(shù)據(jù)庫(kù)中。此時(shí)即使系統(tǒng)崩潰,修改的數(shù)據(jù)也不會(huì)丟失。
事務(wù)的隔離級(jí)別
不可重復(fù)讀"意味著,在數(shù)據(jù)庫(kù)訪問(wèn)中,一個(gè)事務(wù)范圍內(nèi)兩個(gè)相同的查詢卻返回了不同數(shù)據(jù)。這是由于查詢時(shí)系統(tǒng)中其他事務(wù)修改的提交而引起的。 例如:事務(wù)B中對(duì)某個(gè)查詢執(zhí)行兩次,當(dāng)?shù)谝淮螆?zhí)行完時(shí),事務(wù)A對(duì)其數(shù)據(jù)進(jìn)行了修改。事務(wù)B中再次查詢時(shí),數(shù)據(jù)發(fā)生了改變
臟讀意味著一個(gè)事務(wù)讀取了另一個(gè)事務(wù)未提交的數(shù)據(jù),而這個(gè)數(shù)據(jù)是有可能回滾的。
幻讀是指當(dāng)事務(wù)不是獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象,例如第一個(gè)事務(wù)對(duì)一個(gè)表中的數(shù)據(jù)進(jìn)行了修改,這種修改涉及到表中的全部數(shù)據(jù)行。同時(shí),第二個(gè)事務(wù)也修改這個(gè)表中的數(shù)據(jù),這種修改是向表中插入一行新數(shù)據(jù)。那么,以后就會(huì)發(fā)生操作第一個(gè)事務(wù)的用戶發(fā)現(xiàn)表中還有沒(méi)有修改的數(shù)據(jù)行,就好象發(fā)生了幻覺(jué)一樣。
- 讀未提交(Read uncommited)
在該隔離級(jí)別,所有事務(wù)都可以看到其他未提交事務(wù)的執(zhí)行結(jié)果。本隔離級(jí)別很少用于實(shí)際應(yīng)用,因?yàn)樗男阅芤膊槐绕渌?jí)別好多少。除非有特殊的應(yīng)用場(chǎng)景,在一般應(yīng)用中很少使用。 - 讀已提交(Read Committed)
這是大多數(shù)數(shù)據(jù)庫(kù)系統(tǒng)的默認(rèn)隔離級(jí)別(但不是MySQL默認(rèn)的)。它滿足了隔離的簡(jiǎn)單定義:一個(gè)事務(wù)只能看見(jiàn)已經(jīng)提交事務(wù)所做的改變。 - 可重復(fù)讀(Repeatable Read)
這是MySQL的默認(rèn)事務(wù)隔離級(jí)別,它確保同一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí),會(huì)看到同樣的數(shù)據(jù)行。 - 可串行化(Serializable)
這是最高的隔離級(jí)別,它通過(guò)強(qiáng)制事務(wù)排序,使之不可能相互沖突,從而解決幻讀問(wèn)題。簡(jiǎn)言之,它是在每個(gè)讀的數(shù)據(jù)行上加上共享鎖。在這個(gè)級(jí)別,可能導(dǎo)致大量的超時(shí)現(xiàn)象和鎖競(jìng)爭(zhēng)。
四個(gè)隔離級(jí)別可能出現(xiàn)的問(wèn)題:
悲觀鎖和樂(lè)觀鎖
悲觀鎖:顧名思義,就是很悲觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)block直到它拿到鎖。
樂(lè)觀鎖:顧名思義,就是很樂(lè)觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒(méi)有去更新這個(gè)數(shù)據(jù),可以使用版本號(hào)等機(jī)制。
悲觀鎖和樂(lè)觀鎖本質(zhì)區(qū)別在于,一個(gè)對(duì)象被加鎖,悲觀鎖是發(fā)現(xiàn)對(duì)象被加鎖,直接切換上下文,等待對(duì)象解鎖通知;而樂(lè)觀鎖不切換上下文,在那自旋,隔段時(shí)間主動(dòng)詢問(wèn)是否解鎖;
使用場(chǎng)景
悲觀鎖適用于并發(fā)爭(zhēng)搶比較嚴(yán)重的場(chǎng)景;
使用
select * from table where id = 1;
可實(shí)現(xiàn)悲觀鎖;
樂(lè)觀鎖使用于并發(fā)爭(zhēng)搶不太嚴(yán)重的場(chǎng)景;
使用
update table set name = #{test},version = version+1 where id = #{id} and version = #{version}
可實(shí)現(xiàn)樂(lè)觀鎖;
事務(wù)調(diào)優(yōu)原則
- 減少鎖的覆蓋范圍
myisam表鎖--->Innodb行鎖
原位鎖(排他鎖、讀寫(xiě)鎖)--->MVCC多版本 - 增加鎖上課并行的線程數(shù)
讀寫(xiě)分離,允許并發(fā)讀取數(shù)據(jù);可使用ReadWriteLock讀寫(xiě)鎖 - 選擇正確的鎖類(lèi)型
悲觀鎖和樂(lè)觀鎖
MVCC多版本
待續(xù)~~~
切換上下文
目前流行的CPU在同一時(shí)間內(nèi)只能運(yùn)行一個(gè)線程,超線程的處理器可以在同一時(shí)間運(yùn)行多個(gè)線程(包括多核CPU),Linux內(nèi)核會(huì)把多核的處理器當(dāng)作多個(gè)單獨(dú)的CPU來(lái)識(shí)別。
一個(gè)標(biāo)準(zhǔn)的Linux內(nèi)核可以支持運(yùn)行50~50000個(gè)進(jìn)程運(yùn)行,對(duì)于普通的CPU,內(nèi)核會(huì)調(diào)度和執(zhí)行這些進(jìn)程。每個(gè)進(jìn)程都會(huì)分到CPU的時(shí)間片來(lái)運(yùn)行,當(dāng)一個(gè)進(jìn)程用完時(shí)間片或者被更高優(yōu)先級(jí)的進(jìn)程搶占后,它會(huì)備份到CPU的運(yùn)行隊(duì)列中,同時(shí)其他進(jìn)程在CPU上運(yùn)行。這個(gè)進(jìn)程切換的過(guò)程被稱(chēng)作上下文切換。過(guò)多的上下文切換會(huì)造成系統(tǒng)很大的開(kāi)銷(xiāo)。