spring 事務(wù)-使用@Transactional 注解(事務(wù)隔離級(jí)別)

先看下@Transactional可以配制那些參數(shù)及以其所代表的意義。

參數(shù)名 描述
isolation 枚舉org.springframework.transaction.annotation.Isolation的值 事務(wù)隔離級(jí)別
noRollbackFor Class<? extends Throwable>[] 一組異常類,遇到時(shí)不回滾。默認(rèn)為{}
noRollbackForClassName Stirng[] 一組異常類名,遇到時(shí)不回滾,默認(rèn)為{}
propagation 枚舉org.springframework.transaction.annotation.Propagation的值 事務(wù)傳播行為
readOnly boolean 事務(wù)讀寫(xiě)性
rollbackFor Class<? extends Throwable>[] 一組異常類,遇到時(shí)回滾
rollbackForClassName Stirng[] 一組異常類名,遇到時(shí)回滾
timeout 超時(shí)時(shí)間,以秒為單位
value String 可選的限定描述符,指定使用的事務(wù)管理器

isolation事務(wù)隔離級(jí)別,使用時(shí)一般如下。

@Transactional(isolation=Isolation.DEFAULT)
public void method(){}

isolation的參數(shù)有以下五種:
1_1、Isolation.DEFAULT:為數(shù)據(jù)源的默認(rèn)隔離級(jí)別

1_2、isolation=Isolation.READ_UNCOMMITTED:未授權(quán)讀取級(jí)別

以操作同一行數(shù)據(jù)為前提,讀事務(wù)允許其他讀事務(wù)和寫(xiě)事務(wù),未提交的寫(xiě)事務(wù)禁止其他寫(xiě)事務(wù)(但允許其他讀事務(wù))。此隔離級(jí)別可以防止更新丟失,但不能防止臟讀、不可重復(fù)讀、幻讀。此隔離級(jí)別可以通過(guò)“排他寫(xiě)鎖”實(shí)現(xiàn)。

1_3、iIsolation.READ_COMMITTED:授權(quán)讀取級(jí)別

以操作同一行數(shù)據(jù)為前提,讀事務(wù)允許其他讀事務(wù)和寫(xiě)事務(wù),未提交的寫(xiě)事務(wù)禁止其他讀事務(wù)和寫(xiě)事務(wù)。此隔離級(jí)別可以防止更新丟失、臟讀,但不能防止不可重復(fù)讀、幻讀。此隔離級(jí)別可以通過(guò)“瞬間共享讀鎖”和“排他寫(xiě)鎖”實(shí)現(xiàn)。

1_4、iIsolation.REPEATABLE_READ:可重復(fù)讀取級(jí)別

以操作同一行數(shù)據(jù)為前提,讀事務(wù)禁止其他寫(xiě)事務(wù)(但允許其他讀事務(wù)),未提交的寫(xiě)事務(wù)禁止其他讀事務(wù)和寫(xiě)事務(wù)。此隔離級(jí)別可以防止更新丟失、臟讀、不可重復(fù)讀,但不能防止幻讀。此隔離級(jí)別可以通過(guò)“共享讀鎖”和“排他寫(xiě)鎖”實(shí)現(xiàn)。

1_5、iIsolation.SERIALIZABLE:序列化級(jí)別

提供嚴(yán)格的事務(wù)隔離。它要求事務(wù)序列化執(zhí)行,事務(wù)只能一個(gè)接著一個(gè)地執(zhí)行,不能并發(fā)執(zhí)行。此隔離級(jí)別可以防止更新丟失、臟讀、不可重復(fù)讀、幻讀。如果僅僅通過(guò)“行級(jí)鎖”是無(wú)法實(shí)現(xiàn)事務(wù)序列化的,必須通過(guò)其他機(jī)制保證新插入的數(shù)據(jù)不會(huì)被剛執(zhí)行查詢操作的事務(wù)訪問(wèn)到。

隔離級(jí)別越高,越能保證數(shù)據(jù)的完整性和一致性,但是對(duì)并發(fā)性能的影響也越大。對(duì)于多數(shù)應(yīng)用程序,可以優(yōu)先考慮把數(shù)據(jù)庫(kù)系統(tǒng)的隔離級(jí)別設(shè)為Read Committed。它能夠避免更新丟失、臟讀,而且具有較好的并發(fā)性能。盡管它會(huì)導(dǎo)致不可重復(fù)讀、幻讀這些并發(fā)問(wèn)題,在可能出現(xiàn)這類問(wèn)題的個(gè)別場(chǎng)合,可以由應(yīng)用程序采用悲觀鎖或樂(lè)觀鎖來(lái)控制。

數(shù)據(jù)庫(kù)事務(wù)的四大特性(ACID)

ACID,指數(shù)據(jù)庫(kù)事務(wù)正確執(zhí)行的四個(gè)基本要素的縮寫(xiě)。包含:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)。一個(gè)支持事務(wù)(Transaction)的數(shù)據(jù)庫(kù),必需要具有這四種特性,否則在事務(wù)過(guò)程(Transaction processing)當(dāng)中無(wú)法保證數(shù)據(jù)的正確性,交易過(guò)程極可能達(dá)不到交易方的要求。

⑴ 原子性(Atomicity)

第一個(gè)原子性,這個(gè)是最簡(jiǎn)單的。說(shuō)的是一個(gè)事務(wù)內(nèi)所有操作共同組成一個(gè)原子包,要么全部成功,要么全部失敗。這是最基本的特性,保證了因?yàn)橐恍┢渌蛩貙?dǎo)致數(shù)據(jù)庫(kù)異常,或者宕機(jī)。

⑵ 一致性(Consistency)

第二一致性,這個(gè)是大家誤解最深的,很多博客都喜歡用銀行轉(zhuǎn)賬的例子來(lái)講一致性,所謂的一致性是基于原子性。

原子性只保證了一個(gè)事務(wù)內(nèi)的所有操作同一性,大家同生死,不會(huì)出現(xiàn)你死了,我還活著。但是,原子性并沒(méi)有保證大家同一時(shí)刻一起生,一起死。計(jì)算機(jī)指令是有先后順序的,這樣就決定了一個(gè)事務(wù)的提交,會(huì)經(jīng)歷一個(gè)時(shí)間過(guò)程,那么如果事務(wù)提交進(jìn)行到了一半,我讀取了數(shù)據(jù)庫(kù),會(huì)不會(huì)讀到中間結(jié)果?

為了防止這樣的情況,數(shù)據(jù)庫(kù)事務(wù)的一致性就規(guī)定了事務(wù)提交前后,永遠(yuǎn)只可能存在事務(wù)提交前的狀態(tài)和事務(wù)提交后的狀態(tài),從一個(gè)一致性的狀態(tài)到另一個(gè)一致性狀態(tài),而不可能出現(xiàn)中間的過(guò)程態(tài)。也就是說(shuō)事務(wù)的執(zhí)行結(jié)果是量子化狀態(tài),而不是線性狀態(tài)。

數(shù)據(jù)庫(kù)提交事務(wù)會(huì)有一個(gè)過(guò)程,如果提交的時(shí)候,存在一個(gè)時(shí)間差,在提交的第一秒,一個(gè)刪除過(guò)程還沒(méi)完成到了第三秒才完成,會(huì)不會(huì)第一秒訪問(wèn)的人和第三秒訪問(wèn)的人得到不同的結(jié)果?出現(xiàn)不一致,狀態(tài)的混沌?這就是一致性得保證的只會(huì)有前狀態(tài)和后狀態(tài),絕不會(huì)出現(xiàn)中間態(tài)。

⑶ 隔離性(Isolation)

事務(wù)的隔離性,基于原子性和一致性,因?yàn)槭聞?wù)是原子化,量子化的,所以,事務(wù)可以有多個(gè)原子包的形式并發(fā)執(zhí)行,每個(gè)事務(wù)互不干擾。

但是,由于多個(gè)事務(wù)可能操作同一個(gè)資源,不同的事務(wù)為了保證隔離性,會(huì)有很多鎖方案,當(dāng)然這是數(shù)據(jù)庫(kù)的實(shí)現(xiàn),他們?cè)趺磳?shí)現(xiàn)的,我們不必深究。

⑷ 持久性(Durability)

持久性,當(dāng)一個(gè)事務(wù)提交之后,數(shù)據(jù)庫(kù)狀態(tài)永遠(yuǎn)的發(fā)生了改變,這個(gè)事務(wù)只要提交了,哪怕提交后宕機(jī),他也確確實(shí)實(shí)的提交了,不會(huì)出現(xiàn)因?yàn)閯倓傚礄C(jī)了而讓提交不生效,是要事務(wù)提交,他就像洗不掉的紋身,永遠(yuǎn)的固化了,除非你毀了硬盤(pán)。

以上介紹完事務(wù)的四大特性(簡(jiǎn)稱ACID),現(xiàn)在重點(diǎn)來(lái)說(shuō)明下事務(wù)的隔離性,當(dāng)多個(gè)線程都開(kāi)啟事務(wù)操作數(shù)據(jù)庫(kù)中的數(shù)據(jù)時(shí),數(shù)據(jù)庫(kù)系統(tǒng)要能進(jìn)行隔離操作,以保證各個(gè)線程獲取數(shù)據(jù)的準(zhǔn)確性,在介紹數(shù)據(jù)庫(kù)提供的各種隔離級(jí)別之前,我們先看看如果不考慮事務(wù)的隔離性,會(huì)發(fā)生的幾種問(wèn)題:

(1)臟讀

臟讀是指在一個(gè)事務(wù)處理過(guò)程里讀取了另一個(gè)未提交的事務(wù)中的數(shù)據(jù)。
  當(dāng)一個(gè)事務(wù)正在多次修改某個(gè)數(shù)據(jù),而在這個(gè)事務(wù)中這多次的修改都還未提交,這時(shí)一個(gè)并發(fā)的事務(wù)來(lái)訪問(wèn)該數(shù)據(jù),就會(huì)造成兩個(gè)事務(wù)得到的數(shù)據(jù)不一致。例如:用戶A向用戶B轉(zhuǎn)賬100元,對(duì)應(yīng)SQL命令如下

    update account set money=money+100 where name=’B’;  (此時(shí)A通知B)

    update account set money=money - 100 where name=’A’;
(2)不可重復(fù)讀

不可重復(fù)讀是指在對(duì)于數(shù)據(jù)庫(kù)中的某個(gè)數(shù)據(jù),一個(gè)事務(wù)范圍內(nèi)多次查詢卻返回了不同的數(shù)據(jù)值,這是由于在查詢間隔,被另一個(gè)事務(wù)修改并提交了。
  例如事務(wù)T1在讀取某一數(shù)據(jù),而事務(wù)T2立馬修改了這個(gè)數(shù)據(jù)并且提交事務(wù)給數(shù)據(jù)庫(kù),事務(wù)T1再次讀取該數(shù)據(jù)就得到了不同的結(jié)果,發(fā)送了不可重復(fù)讀。
  不可重復(fù)讀和臟讀的區(qū)別是,臟讀是某一事務(wù)讀取了另一個(gè)事務(wù)未提交的臟數(shù)據(jù),而不可重復(fù)讀則是讀取了前一事務(wù)提交的數(shù)據(jù)。
  在某些情況下,不可重復(fù)讀并不是問(wèn)題,比如我們多次查詢某個(gè)數(shù)據(jù)當(dāng)然以最后查詢得到的結(jié)果為主。但在另一些情況下就有可能發(fā)生問(wèn)題,例如對(duì)于同一個(gè)數(shù)據(jù)A和B依次查詢就可能不同,A和B就可能打起來(lái)了……

(3)虛讀(幻讀)

幻讀是事務(wù)非獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象。例如事務(wù)T1對(duì)一個(gè)表中所有的行的某個(gè)數(shù)據(jù)項(xiàng)做了從“1”修改為“2”的操作,這時(shí)事務(wù)T2又對(duì)這個(gè)表中插入了一行數(shù)據(jù)項(xiàng),而這個(gè)數(shù)據(jù)項(xiàng)的數(shù)值還是為“1”并且提交給數(shù)據(jù)庫(kù)。而操作事務(wù)T1的用戶如果再查看剛剛修改的數(shù)據(jù),會(huì)發(fā)現(xiàn)還有一行沒(méi)有修改,其實(shí)這行是從事務(wù)T2中添加的,就好像產(chǎn)生幻覺(jué)一樣,這就是發(fā)生了幻讀。

幻讀和不可重復(fù)讀都是讀取了另一條已經(jīng)提交的事務(wù)(這點(diǎn)就臟讀不同),所不同的是不可重復(fù)讀查詢的都是同一個(gè)數(shù)據(jù)項(xiàng),而幻讀針對(duì)的是一批數(shù)據(jù)整體(比如數(shù)據(jù)的個(gè)數(shù))。

現(xiàn)在來(lái)看看MySQL數(shù)據(jù)庫(kù)為我們提供的四種隔離級(jí)別:
  ① Serializable (串行化):可避免臟讀、不可重復(fù)讀、幻讀的發(fā)生。---鎖表
  這是數(shù)據(jù)庫(kù)最高的隔離級(jí)別,這種級(jí)別下,事務(wù)“串行化順序執(zhí)行”,也就是一個(gè)一個(gè)排隊(duì)執(zhí)行。
  這種級(jí)別下,“臟讀”、“不可重復(fù)讀”、“幻讀”都可以被避免,但是執(zhí)行效率奇差,性能開(kāi)銷也最大,所以基本沒(méi)人會(huì)用。
 ?、?Repeatable read (可重復(fù)讀):可避免臟讀、不可重復(fù)讀的發(fā)生。---鎖行
  可重復(fù)讀,顧名思義,就是專門(mén)針對(duì)“不可重復(fù)讀”這種情況而制定的隔離級(jí)別,自然,它就可以有效的避免“不可重復(fù)讀”。而它也是MySql的默認(rèn)隔離級(jí)別。
  在這個(gè)級(jí)別下,普通的查詢同樣是使用的“快照讀”,但是,和“讀提交”不同的是,當(dāng)事務(wù)啟動(dòng)時(shí),就不允許進(jìn)行“修改操作(Update)”了,而“不可重復(fù)讀”恰恰是因?yàn)閮纱巫x取之間進(jìn)行了數(shù)據(jù)的修改,因此,“可重復(fù)讀”能夠有效的避免“不可重復(fù)讀”,但卻避免不了“幻讀”,因?yàn)榛米x是由于“插入或者刪除操作(Insert or Delete)”而產(chǎn)生的。
 ?、?Read committed (讀已提交):可避免臟讀的發(fā)生。
  這是各種系統(tǒng)中最常用的一種隔離級(jí)別,也是SQL Server和Oracle的默認(rèn)隔離級(jí)別。這種隔離級(jí)別能夠有效的避免臟讀,但除非在查詢中顯示的加鎖,如:
  select * from T where ID=2 lock in share mode;
  select * from T where ID=2 for update;
  不然,普通的查詢是不會(huì)加鎖的。
  那為什么“讀提交”同“讀未提交”一樣,都沒(méi)有查詢加鎖,但是卻能夠避免臟讀呢?
  這就要說(shuō)道另一個(gè)機(jī)制“快照(snapshot)”,而這種既能保證一致性又不加鎖的讀也被稱為“快照讀(Snapshot Read)”
  假設(shè)沒(méi)有“快照讀”,那么當(dāng)一個(gè)更新的事務(wù)沒(méi)有提交時(shí),另一個(gè)對(duì)更新數(shù)據(jù)進(jìn)行查詢的事務(wù)會(huì)因?yàn)闊o(wú)法查詢而被阻塞,這種情況下,并發(fā)能力就相當(dāng)?shù)牟睢?br>   而“快照讀”就可以完成高并發(fā)的查詢,不過(guò),“讀提交”只能避免“臟讀”,并不能避免“不可重復(fù)讀”和“幻讀”。
 ?、?Read uncommitted (讀未提交):最低級(jí)別,任何情況都無(wú)法保證。
  
  為什么會(huì)出現(xiàn)“臟讀”?因?yàn)闆](méi)有“select”操作沒(méi)有規(guī)矩。
  為什么會(huì)出現(xiàn)“不可重復(fù)讀”?因?yàn)椤皍pdate”操作沒(méi)有規(guī)矩。
  為什么會(huì)出現(xiàn)“幻讀”?因?yàn)椤癷nsert”和“delete”操作沒(méi)有規(guī)矩。
  “讀未提(Read Uncommitted)”能預(yù)防啥?啥都預(yù)防不了。
  “讀提交(Read Committed)”能預(yù)防啥?使用“快照讀(Snapshot Read)”,避免“臟讀”,但是可能出現(xiàn)“不可重復(fù)讀”和“幻讀”。
  “可重復(fù)讀(Repeated Red)”能預(yù)防啥?使用“快照讀(Snapshot Read)”,鎖住被讀取記錄,避免出現(xiàn)“臟讀”、“不可重復(fù)讀”,但是可能出現(xiàn)“幻讀”。
  “串行化(Serializable)”能預(yù)防啥?排排坐,吃果果,有效避免“臟讀”、“不可重復(fù)讀”、“幻讀”,不過(guò)效果誰(shuí)用誰(shuí)知道。

以上四種隔離級(jí)別最高的是Serializable級(jí)別,最低的是Read uncommitted級(jí)別,當(dāng)然級(jí)別越高,執(zhí)行效率就越低。像Serializable這樣的級(jí)別,就是以鎖表的方式(類似于Java多線程中的鎖)使得其他的線程只能在鎖外等待,所以平時(shí)選用何種隔離級(jí)別應(yīng)該根據(jù)實(shí)際情況。在MySQL數(shù)據(jù)庫(kù)中默認(rèn)的隔離級(jí)別為Repeatable read (可重復(fù)讀)。

在MySQL數(shù)據(jù)庫(kù)中,支持上面四種隔離級(jí)別,默認(rèn)的為Repeatable read (可重復(fù)讀);而在Oracle數(shù)據(jù)庫(kù)中,只支持Serializable (串行化)級(jí)別和Read committed (讀已提交)這兩種級(jí)別,其中默認(rèn)的為Read committed級(jí)別。

小科普:

事務(wù)的原子性是通過(guò)undo log(MVCC)實(shí)現(xiàn)
事務(wù)的持久性是通過(guò)redo log實(shí)現(xiàn)
事務(wù)的隔離性是通過(guò)讀寫(xiě)鎖+MVCC來(lái)實(shí)現(xiàn)
事務(wù)的一致性是通過(guò)原子性、持久性和隔離性來(lái)實(shí)現(xiàn)的

參考博客:
https://blog.csdn.net/a317677438a/article/details/52186947
http://www.itdecent.cn/p/2a77146e70b4
https://www.cnblogs.com/fjdingsd/p/5273008.html
https://baijiahao.baidu.com/s?id=1611918898724887602&wfr=spider&for=pc

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容