spring聲明式事務(wù)

1.數(shù)據(jù)庫ACID、事務(wù)隔離級別

2.spring事務(wù)相關(guān)的API

3.spring聲明式事務(wù)

4.spring事務(wù)傳播行為

5.sring事務(wù)原理


1.數(shù)據(jù)庫ACID、事務(wù)隔離級別

此章節(jié)作為理論基礎(chǔ)先行篇。
事務(wù)四個特性:
①原子性(Atomicity)
sql作為一個整體,要么全部成功,要么全部失敗回滾。
②一致性(Consistency)
sql的執(zhí)行完之后保持整體的一致性。
③隔離性(Isolation)
用于并發(fā)控制,實現(xiàn)并發(fā)執(zhí)行的事務(wù)能夠按照順序執(zhí)行
④持久性(Durability)
事務(wù)提交后,數(shù)據(jù)會持久化到磁盤中

在高并發(fā)場景下,要完全滿足ACID是很困難的,除非將事務(wù)的執(zhí)行設(shè)置為串行化,但是這樣會導(dǎo)致性能下降,因此根據(jù)業(yè)務(wù)場景不同對事務(wù)的要求不同,數(shù)據(jù)庫設(shè)計了四種隔離級別,供用戶自行選擇。

隔離級別 臟讀 不可重復(fù)度 幻讀
讀未提交(read uncommitted)
讀已提交(read committed)oracle默認(rèn)隔離級別 ?
可重復(fù)讀(repeatable read)mysql默認(rèn)隔離級別 ? ?
串行化(serializable) ? ? ?
讀未提交:

事務(wù)A可以讀取其他事務(wù)未提交的修改


讀未提交
讀已提交:

事務(wù)A只能讀取其他事務(wù)已提交的修改


讀已提交
可重復(fù)讀:

事務(wù)A在開啟事務(wù)后,所讀取的數(shù)據(jù)①當(dāng)前事務(wù)未修改的數(shù)據(jù)讀取的結(jié)果是開啟事務(wù)之前一致②當(dāng)前事務(wù)修改的數(shù)據(jù)再次讀取是當(dāng)前事務(wù)修改的值。


可重復(fù)讀
串行化

數(shù)據(jù)庫每次讀寫都會加鎖,讀讀鎖不會產(chǎn)生沖突,讀寫鎖,寫寫鎖時會產(chǎn)生沖突,例如下圖,事務(wù)讀取改行數(shù)據(jù)時會加讀鎖,導(dǎo)致事務(wù)B掛起,當(dāng)事務(wù)A commit后釋放讀鎖,事務(wù)B繼續(xù)執(zhí)行。


串行化

不同的數(shù)據(jù)隔離級別可能會導(dǎo)致的問題解釋:
臟讀:

當(dāng)前事務(wù)讀取了其他事務(wù)未提交的修改數(shù)據(jù)

不可重復(fù)讀:

當(dāng)前事務(wù)前后讀取的同一條數(shù)據(jù)結(jié)果不一致。

幻讀:

當(dāng)前事務(wù)內(nèi),讀取一個范圍內(nèi)的記錄,前后結(jié)果不一致(記錄減少或記錄增加)
比如select count(1) from table T where a>1 結(jié)果為5,在當(dāng)前事務(wù)內(nèi)再次執(zhí)行發(fā)現(xiàn)結(jié)果為10

對于隔離級別為可重復(fù)讀下,mysql通過MVCC(多版本并發(fā)控制)基本可以幫我們解決掉幻讀問題,但是對于update/delete問題還是解決不了的。
讀提交、不可重復(fù)讀 的隔離級別之所以可以將數(shù)據(jù)隔離,是因為數(shù)據(jù)庫引擎引入的視圖(read-view)的概念,可以對數(shù)據(jù)生成快照,結(jié)合回滾日志實現(xiàn)的。
此處只是簡單提一下,目前打算放在之后數(shù)據(jù)庫專欄分析該問題。

2.spring事務(wù)相關(guān)的API

TransactionDefinition 事務(wù)定義相關(guān)類
PlatformTransactionManager 事務(wù)管理類
TransactionStatus 事務(wù)運行時相關(guān)的狀態(tài)

TransactionDefinition

PlatformTransactionManager

TransactionStatus

3.spring聲明式事務(wù)

為了簡化對事物的控制,spring提出了聲明式事務(wù),簡化了對事務(wù)的操作。

  • spring配置文件
<!--配置包掃描-->
    <context:component-scan base-package="com.ckd"/>
    <!--配置數(shù)據(jù)源-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://master:3306/dck"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
     <!--JDBCTemplate-->
    <bean class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="datasource"/>
    </bean>
    <!--配置事務(wù)管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>
      <!--支持事務(wù)注解-->
    <tx:annotation-driven transaction-manager="txManager"/>

之后就可以用@Transactionnal注解了

4.spring事務(wù)傳播行為
類別 事務(wù)傳播行為 說明
支持當(dāng)前事務(wù) PROPAGATION_REQUIRED 當(dāng)前存在事務(wù),則加入到該事務(wù)中,沒事務(wù)的話,新建一個事務(wù)(默認(rèn)傳播行為)
~ PROPAGATION_SUPPORTS 當(dāng)前存在事務(wù)加入到該事務(wù)中,如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式運行
~ PROPAGATION_MANDATORY 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),則拋出異常
不支持當(dāng)前事務(wù) PROPAGATION_REQUIRES_NEW 不管當(dāng)前有沒有事務(wù),都會新建一個事務(wù)
~ PROPAGATION_NOT_SUPPORT 以非事務(wù)的方式運行,如果當(dāng)前存在事務(wù),則將當(dāng)前事務(wù)掛起
~ PROPAGATION_NEVER 以非事務(wù)的方式運行,如果當(dāng)前存在事務(wù),則拋出異常
嵌套事務(wù) PROPAGATION_NESTED 如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒有事務(wù),則進(jìn)行與PROPAGATION_REQUIRED類似的操作

PROPAGATION_REQUIRES_NEW、 PROPAGATION_NESTED這兩個事務(wù)比較疑惑,因此單獨提出來分析一下。

PROPAGATION_REQUIRES_NEW:

如下圖在同一個線程中,在執(zhí)行MethodA()時開啟一個事務(wù),調(diào)用serviceB.methodB()時會重新開啟一個事務(wù),執(zhí)行methodA時的事務(wù)暫時掛起,由AbstractPlatformTransactionManager負(fù)責(zé)相應(yīng)的線程及事務(wù)信息的保存處理(具體源碼沒研究過)。MethodB()執(zhí)行完commit之后,MethodA恢復(fù)之前事務(wù)狀態(tài),繼續(xù)執(zhí)行。
因此結(jié)論是:
MethodB執(zhí)行的異?;貪L并不會影響methodA的回滾操作,兩個事務(wù)互不影響。

class ServiceA{
       @Transactional(propagation = Propagation.REQUIRED)
       methodA(){
              serviceB.methodB();
       }
}
class ServiceB{
       @Transactional(propagation = Propagation.REQUIRES_NEW)
       methodB(){
       }
}
PROPAGATION_NESTED:

PROPAGATION_NESTED作為一個嵌套事務(wù),實際上是serviceB.methodB()作為methodA執(zhí)行時開啟的事務(wù)的一個子事務(wù),兩者本質(zhì)上是同一個事務(wù),在執(zhí)行到serviceB.methodB()會通過savePoint(參見TransactionStatus類)機(jī)制記錄執(zhí)行位置,當(dāng)methodB發(fā)生異常時,會通過savePoint將methodB執(zhí)行的sql語句回滾,methodA并不受影響(前提時異常捕獲了)。

class ServiceA{
       @Transactional(propagation = Propagation.REQUIRED)
       methodA(){
              serviceB.methodB();
       }
}
class ServiceB{
       @Transactional(propagation = Propagation.NESTED)       
       methodB(){
       }
}

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

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