ACID:原子性(Atomicity)屹堰、一致性(Consistency)、隔離性(Isolation)街氢、持久性(Durability)
原子性:是指事務(wù)包含的所有操作要么全部成功,要么全部失敗回滾珊肃,因此事務(wù)的操作如果成功就必須要完全應(yīng)用到數(shù)據(jù)庫荣刑,如果操作失敗則不能對數(shù)據(jù)庫有任何影響。
一致性:是指事務(wù)必須使數(shù)據(jù)庫從一個一致性狀態(tài)變換到另一個一致性狀態(tài)伦乔,也就是說一個事務(wù)執(zhí)行之前和執(zhí)行之后都必須處于一致性狀態(tài)厉亏。
隔離性:是當(dāng)多個用戶并發(fā)訪問數(shù)據(jù)庫時,比如操作同一張表時烈和,數(shù)據(jù)庫為每一個用戶開啟的事務(wù)爱只,不能被其他事務(wù)的操作所干擾,多個并發(fā)事務(wù)之間要相互隔離斥杜。
持久性:是指一個事務(wù)一旦被提交了虱颗,那么對數(shù)據(jù)庫中的數(shù)據(jù)的改變就是永久性的,即便是在數(shù)據(jù)庫系統(tǒng)遇到故障的情況下也不會丟失提交事務(wù)的操作蔗喂。
個人理解據(jù)庫事務(wù)主要做了兩件事情:
一是保證一致性結(jié)果,能在發(fā)生異常的時候快速恢復(fù),也就是回滾
二是并發(fā)訪問的時候提供隔離
隔離級別 | 臟讀 | 不可重復(fù)讀 | 幻讀 |
---|---|---|---|
未提交讀Read Uncommitted | 是 | 是 | 是 |
已提交讀Read Committed | 否 | 是 | 是 |
可重復(fù)讀Repeatable Read | 否 | 否 | 是 |
可串行化Serializable | 否 | 否 | 否 |
讀未提交:就是一個事務(wù)可以讀取另一個未提交事務(wù)的數(shù)據(jù)忘渔。
讀提交:就是一個事務(wù)要等另一個事務(wù)提交后才能讀取數(shù)據(jù)。若有事務(wù)對數(shù)據(jù)進(jìn)行更新(UPDATE)操作時缰儿,讀操作事務(wù)要等待這個更新操作事務(wù)提交后才能讀取數(shù)據(jù)畦粮,可以解決臟讀問題。
重復(fù)讀:就是在開始讀取數(shù)據(jù)(事務(wù)開啟)時乖阵,不再允許修改操作宣赔。重復(fù)讀可以解決不可重復(fù)讀問題。寫到這里瞪浸,應(yīng)該明白的一點(diǎn)就是儒将,不可重復(fù)讀對應(yīng)的是修改,即UPDATE操作对蒲。但是可能還會有幻讀問題钩蚊。因?yàn)榛米x問題對應(yīng)的是插入INSERT操作贡翘,而不是UPDATE操作。
Serializable:是最高的事務(wù)隔離級別砰逻,在該級別下鸣驱,事務(wù)串行化順序執(zhí)行,可以避免臟讀蝠咆、不可重復(fù)讀與幻讀踊东。但是這種事務(wù)隔離級別效率低下,比較耗數(shù)據(jù)庫性能刚操,一般不使用闸翅。
mysql 對應(yīng)的InnoDB默認(rèn)隔離級別是 重復(fù)讀
明細(xì)可以參考:https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html
隔離怎么實(shí)現(xiàn)?
隔離的實(shí)現(xiàn)也是依賴加鎖機(jī)制, InnoDB存在兩種鎖:
共享鎖(S鎖) :(插入/修改/刪除)資源獲取S鎖之后赡茸,能加S鎖缎脾,不能加X鎖
排它鎖(X鎖) : 資源加上X鎖之后,不能加S鎖占卧,也不能加X鎖
S/X鎖兼容表
鎖定類型 | 讀鎖 | 寫鎖 |
---|---|---|
讀鎖 | Compatible | Conflict |
寫鎖 | Conflict | Conflict |
具體的四種隔離級別鎖實(shí)現(xiàn):
隔離級別 | 操作 | 鎖 | 生命周期 |
---|---|---|---|
讀未提交 | 讀 | 否 | |
讀未提交 | 寫 | 行級排它鎖 | 立即釋放 |
讀已提交 | 讀 | 行級共享鎖 | 立即釋放 |
讀已提交 | 寫 | 行級排它鎖 | 事務(wù)結(jié)束 |
可重復(fù)讀 | 讀 | 行級共享鎖 | 事務(wù)結(jié)束 |
可重復(fù)讀 | 寫 | 行級排它鎖 | 事務(wù)結(jié)束 |
可串行化 | 讀 | 范圍鎖/表級別鎖 | 事務(wù)結(jié)束 |
可串行化 | 寫 | 行級排它鎖 | 事務(wù)結(jié)束 |
讀未提交
為了解決丟失更新問題,需要對寫操作加 X 鎖
讀已提交
為了保證讀已提交遗菠,讀操作加上 S 鎖,這樣如果其他事務(wù)有正在寫的操作华蜒,必須等待寫操作提交之后才能讀辙纬,因?yàn)?S 和 X 互斥,如果在讀的過程中其他事務(wù)想寫叭喜,也必須等事務(wù)讀完之后才可以贺拣。這里的 S 鎖是一個臨時 S 鎖,表示事務(wù)讀完之后立即釋放該鎖捂蕴,可以讓其他事務(wù)繼續(xù)寫譬涡,如果事務(wù)再讀的話,就可能讀到不一樣的記錄啥辨,這就是 不可重復(fù)讀 了涡匀。
可重復(fù)讀
為了讓事務(wù)可以重復(fù)讀,加在讀操作的 S 鎖變成了持續(xù) S 鎖溉知,也就是直到事務(wù)結(jié)束時才釋放該鎖陨瘩,這可以保證整個事務(wù)過程中,其他事務(wù)無法進(jìn)行寫操作级乍,所以每次讀出來的記錄是一樣的舌劳。
可串行化
序列化隔離級別下單純的使用行鎖已經(jīng)實(shí)現(xiàn)不了,因?yàn)樾墟i不能阻止其他事務(wù)的插入操作玫荣,這就會導(dǎo)致幻讀問題甚淡,這種情況下,我們可以把鎖加到表上或者使用范圍鎖(間隙鎖)捅厂。
通過對鎖的類型(讀鎖還是寫鎖)贯卦,鎖的粒度(行鎖還是表鎖)底挫,持有鎖的時間(臨時鎖還是持續(xù)鎖)合理的進(jìn)行組合,就可以實(shí)現(xiàn)四種不同的隔離級別.這四種不同的加鎖策略實(shí)際上又稱為 封鎖協(xié)議(Locking Protocol)
Spring事務(wù)隔離級別
- ISOLATION_DEFAULT這是一個PlatfromTransactionManager默認(rèn)的隔離級別脸侥,使用數(shù)據(jù)庫默認(rèn)的事務(wù)隔離級別。另外四個與JDBC的隔離級別相對應(yīng) 。默認(rèn)采用的是重復(fù)讀,除了insert幻讀外基本的場景都能cover
- ISOLATION_READ_UNCOMMITTED 這是事務(wù)最低的隔離級別,它充許別外一個事務(wù)可以看到這個事務(wù)未提交的數(shù)據(jù)赂鲤。這種隔離級別會產(chǎn)生臟讀字逗,不可重復(fù)讀和幻像讀
- ISOLATION_READ_COMMITTED 保證一個事務(wù)修改的數(shù)據(jù)提交后才能被另外一個事務(wù)讀取。另外一個事務(wù)不能讀取該事務(wù)未提交的數(shù)據(jù)洛搀。這種事務(wù)隔離級別可以避免臟讀出現(xiàn),但是可能會出現(xiàn)不可重復(fù)讀和幻像讀。
- ISOLATION_REPEATABLE_READ 這種事務(wù)隔離級別可以防止臟讀跳仿,不可重復(fù)讀。但是可能出現(xiàn)幻像讀捐晶。它除了保證一個事務(wù)不能讀取另一個事務(wù)未提交的數(shù)據(jù)外菲语,還保證了避免下面的情況產(chǎn)生(不可重復(fù)讀)。
- ISOLATION_SERIALIZABLE 這是花費(fèi)最高代價但是最可靠的事務(wù)隔離級別惑灵。事務(wù)被處理為順序執(zhí)行山上。除了防止臟讀,不可重復(fù)讀外英支,還避免了幻像讀佩憾。
Spring事務(wù)傳播級別
- PROPAGATION_REQUIRED 如果存在一個事務(wù),則支持當(dāng)前事務(wù)干花。如果沒有事務(wù)則開啟一個新的事務(wù)妄帘。
- PROPAGATION_SUPPORTS 如果存在一個事務(wù),支持當(dāng)前事務(wù)池凄。如果沒有事務(wù)抡驼,則非事務(wù)的執(zhí)行。但是對于事務(wù)同步的事務(wù)管理器修赞,PROPAGATION_SUPPORTS與不使用事務(wù)有少許不同婶恼。
- PROPAGATION_MANDATORY 如果已經(jīng)存在一個事務(wù),支持當(dāng)前事務(wù)柏副。如果沒有一個活動的事務(wù)勾邦,則拋出異常。
- PROPAGATION_REQUIRES_NEW 總是開啟一個新的事務(wù)割择。如果一個事務(wù)已經(jīng)存在眷篇,則將這個存在的事務(wù)掛起。當(dāng)數(shù)據(jù)庫分庫分表存在跨庫的時候需要啟用
- PROPAGATION_NOT_SUPPORTED 總是非事務(wù)地執(zhí)行荔泳,并掛起任何存在的事務(wù)蕉饼。
- PROPAGATION_NEVER 總是非事務(wù)地執(zhí)行虐杯,如果存在一個活動事務(wù),則拋出異常昧港。
-
PROPAGATION_NESTED 如果一個活動的事務(wù)存在擎椰,則運(yùn)行在一個嵌套的事務(wù)中. 如果沒有活動事務(wù), 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執(zhí)行。
demo如下
<!--事務(wù)模板 -->
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager">
<ref local="transactionManager" />
</property>
<!--ISOLATION_DEFAULT 表示由使用的數(shù)據(jù)庫決定 -->
<property name="isolationLevelName" value="ISOLATION_DEFAULT"/>
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
</bean>