一文搞清楚Spring事務(wù)
什么是Spring事務(wù)?
Spring事務(wù)是指在Spring框架中對(duì)于數(shù)據(jù)庫操作的一種支持,它通過對(duì)一組數(shù)據(jù)庫操作進(jìn)行整體控制來保證數(shù)據(jù)的一致性和完整性。Spring事務(wù)可以保證在一組數(shù)據(jù)庫操作執(zhí)行時(shí),要么所有操作都執(zhí)行成功,要么所有操作都回滾到之前的狀態(tài),從而避免了數(shù)據(jù)不一致的情況。
Spring事務(wù)實(shí)現(xiàn)方式
Spring事務(wù)可以通過編程式事務(wù)和聲明式事務(wù)兩種方式來實(shí)現(xiàn)。編程式事務(wù)需要在代碼中手動(dòng)控制事務(wù)的開始、提交和回滾等操作,而聲明式事務(wù)則是通過在配置文件中聲明事務(wù)的切入點(diǎn)和通知等信息來自動(dòng)控制事務(wù)的行為。
Spring編程式事務(wù)
Spring編程式事務(wù)需要在代碼中獲取事務(wù)管理器,并通過該事務(wù)管理器獲取事務(wù)對(duì)象,然后使用該事務(wù)對(duì)象來控制事務(wù)的開始、提交和回滾等操作。
public void transferMoney(Account fromAccount, Account toAccount, double amount) {
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
fromAccount.withdraw(amount);
toAccount.deposit(amount);
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
}
}在上面的代碼中,首先通過transactionManager.getTransaction方法獲取事務(wù)對(duì)象status,然后在try塊中執(zhí)行轉(zhuǎn)賬操作,最后通過transactionManager.commit(status)提交事務(wù)。如果在轉(zhuǎn)賬操作中發(fā)生了異常,則會(huì)通過transactionManager.rollback(status)回滾事務(wù)。
編程式事務(wù)的優(yōu)點(diǎn)是靈活性高,可以根據(jù)具體的業(yè)務(wù)需求來靈活控制事務(wù)的行為。不過缺點(diǎn)是代碼冗長(zhǎng),可讀性差,而且容易出現(xiàn)錯(cuò)誤。
Spring聲明式事務(wù)
Spring聲明式事務(wù)需要在配置文件中聲明事務(wù)管理器、事務(wù)通知等元素,然后在需要使用事務(wù)的方法上添加事務(wù)切面的注解即可。
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transferMoney" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="transferPointcut" expression="execution(* com.example.TransferService.transferMoney(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="transferPointcut"/>
</aop:config>在上面的配置文件中,首先聲明了事務(wù)管理器transactionManager,然后定義了事務(wù)通知txAdvice,該通知會(huì)在transferMoney方法執(zhí)行時(shí)進(jìn)行事務(wù)管理。最后通過aop:config和aop:advisor來將txAdvice應(yīng)用于transferPointcut定義的切入點(diǎn)上。
聲明式事務(wù)的優(yōu)點(diǎn)是通過配置文件來管理事務(wù),避免了在代碼中手動(dòng)控制事務(wù)的繁瑣和容易出錯(cuò)的問題。不過缺點(diǎn)是靈活性較差,不能根據(jù)具體的業(yè)務(wù)需求來靈活控制事務(wù)的行為。
聲明式事務(wù)注解方式
Spring聲明式事務(wù)也可以通過注解的方式來實(shí)現(xiàn)。具體來說,可以在需要使用事務(wù)的方法上添加@Transactional注解,并通過該注解的屬性來指定事務(wù)的傳播機(jī)制、隔離級(jí)別、超時(shí)時(shí)間等信息。
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 3600)
public void transferMoney(Account fromAccount, Account toAccount, double amount) {
fromAccount.withdraw(amount);
toAccount.deposit(amount);
}在上面的代碼中,通過@Transactional注解來聲明了事務(wù)的傳播機(jī)制為Propagation.REQUIRED,隔離級(jí)別為Isolation.DEFAULT,超時(shí)時(shí)間為3600秒。在方法執(zhí)行時(shí),Spring會(huì)根據(jù)注解中的信息自動(dòng)管理事務(wù)的行為。
注解式聲明事務(wù)的優(yōu)點(diǎn)是代碼簡(jiǎn)潔、可讀性好,靈活性和可用性高,容易維護(hù)和調(diào)試。但是它也有一些缺點(diǎn),例如注解的使用可能會(huì)導(dǎo)致代碼分散,而且無法通過配置文件來管理事務(wù),而且可能會(huì)引入一些意想不到的問題。
@Transactional注解的常用參數(shù)包括:
value:該屬性可以用來指定事務(wù)管理器的名稱,如果只有一個(gè)事務(wù)管理器,則可以省略該屬性。propagation:該屬性用于指定事務(wù)的傳播機(jī)制,包括REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER和NESTED共7種。isolation:該屬性用于指定事務(wù)的隔離級(jí)別,包括DEFAULT、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ和SERIALIZABLE共5種。timeout:該屬性用于指定事務(wù)的超時(shí)時(shí)間,單位為秒,默認(rèn)值為-1,表示沒有超時(shí)限制。readOnly:該屬性用于指定事務(wù)是否為只讀事務(wù),默認(rèn)值為false,表示事務(wù)可讀可寫。rollbackFor:該屬性用于指定事務(wù)回滾的條件,如果出現(xiàn)指定的異常類型,則事務(wù)會(huì)回滾。noRollbackFor:該屬性用于指定事務(wù)不回滾的條件,如果出現(xiàn)指定的異常類型,則事務(wù)不會(huì)回滾。
除了上述常用參數(shù)外,@Transactional注解還有其他一些參數(shù),例如transactionManager、rollbackForClassName、noRollbackForClassName和value等,具體用法可以參考Spring官方文檔。
在使用@Transactional注解時(shí),需要根據(jù)具體的業(yè)務(wù)需求來選擇合適的參數(shù),以保證事務(wù)的正確性和可靠性。
事務(wù)注解失效情況
Spring的聲明式事務(wù)注解可能失效的情況包括:
- 注解被錯(cuò)誤地放置在了類上而不是方法上。
- 方法是private或final的,而且它們不能從外部調(diào)用。
- 方法沒有被公開暴露,也就是說,它們不是公開的方法(public)。
- 被注解的方法是靜態(tài)的。
- 被注解的方法依賴于其他未被注解的方法(例如,被注解的方法調(diào)用了一個(gè)未被注解的私有方法)。
- 被注解的方法在另一個(gè)類中被調(diào)用。
- 注解被錯(cuò)誤地配置了,例如使用了錯(cuò)誤的名稱或參數(shù)。
- 類沒有被正確地掃描,因此Spring無法找到應(yīng)該被注解的方法。
- 注解屬性propagation設(shè)置錯(cuò)誤
- 注解屬性rollbackFor設(shè)置錯(cuò)誤
- 異常被catch捕獲導(dǎo)致@Transactional失效
- 數(shù)據(jù)庫引擎不支持事務(wù)
- 多個(gè)切面的影響也會(huì)導(dǎo)致事務(wù)失效
如果遇到聲明式事務(wù)注解失效的情況,需要檢查上述問題并進(jìn)行相應(yīng)的修復(fù)。
代碼規(guī)范中強(qiáng)調(diào)
@Transactional事務(wù)不要濫用。事務(wù)會(huì)影響數(shù)據(jù)庫的QPS,另外使用事務(wù)的敵方需要考慮各方面的回滾方案,包括緩存回滾、搜索引擎、消息補(bǔ)償、統(tǒng)計(jì)修正等。
在使用Spring事務(wù)時(shí),需要注意對(duì)于事務(wù)的傳播機(jī)制和隔離級(jí)別的設(shè)置,以及對(duì)于事務(wù)的異常處理等問題。正確地使用Spring事務(wù)可以提高系統(tǒng)的數(shù)據(jù)一致性和可靠性。
什么是Spring事務(wù)傳播機(jī)制
Spring事務(wù)傳播機(jī)制是指在多個(gè)事務(wù)操作發(fā)生時(shí),如何管理這些操作之間的事務(wù)關(guān)系。Spring事務(wù)傳播機(jī)制可以通過Propagation枚舉類中的不同值來指定,共包括七種不同的傳播行為。具體來說,Spring事務(wù)傳播機(jī)制包括以下七種:
REQUIRED:如果當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新的事務(wù);如果當(dāng)前已經(jīng)存在事務(wù),則加入該事務(wù)。這是默認(rèn)的傳播行為。SUPPORTS:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式執(zhí)行。MANDATORY:必須在一個(gè)已存在的事務(wù)中執(zhí)行,否則就拋出TransactionRequiredException異常。REQUIRES_NEW:創(chuàng)建一個(gè)新的事務(wù),并在該事務(wù)中執(zhí)行;如果當(dāng)前存在事務(wù),則將當(dāng)前事務(wù)掛起。NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),則將當(dāng)前事務(wù)掛起。NEVER:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),則拋出IllegalTransactionStateException異常。NESTED:如果當(dāng)前存在事務(wù),則在嵌套事務(wù)中執(zhí)行;如果當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。
在使用Spring事務(wù)傳播機(jī)制時(shí),需要根據(jù)具體的業(yè)務(wù)需求來選擇合適的傳播行為,以保證事務(wù)的正確性和可靠性。同時(shí),需要注意事務(wù)的異常處理等問題,以避免數(shù)據(jù)不一致或丟失的情況發(fā)生。
@Transactional注解中的傳播機(jī)制
除了在代碼中使用編程式事務(wù)和聲明式事務(wù)外,Spring還提供了@Transactional注解來實(shí)現(xiàn)事務(wù)控制。在使用@Transactional注解時(shí),可以通過propagation屬性來指定事務(wù)的傳播機(jī)制,例如:
@Transactional(propagation = Propagation.REQUIRED)
public void transferMoney(Account fromAccount, Account toAccount, double amount) {
fromAccount.withdraw(amount);
toAccount.deposit(amount);
}在上面的代碼中,通過propagation屬性來指定了事務(wù)的傳播機(jī)制為Propagation.REQUIRED,即如果當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新的事務(wù);如果當(dāng)前已經(jīng)存在事務(wù),則加入該事務(wù)。
除了Propagation枚舉類中的七種傳播行為外,@Transactional注解還可以通過isolation、timeout、readOnly等屬性來指定事務(wù)的隔離級(jí)別、超時(shí)時(shí)間和只讀事務(wù)等信息。
在使用@Transactional注解時(shí),需要根據(jù)具體的業(yè)務(wù)需求來選擇合適的傳播行為和其他屬性,以保證事務(wù)的正確性和可靠性。
Spring事務(wù)的隔離級(jí)別
Spring事務(wù)的隔離級(jí)別是指多個(gè)事務(wù)之間的隔離程度,它可以通過設(shè)置isolation屬性來指定。Spring事務(wù)的隔離級(jí)別包括以下五種:
DEFAULT:默認(rèn)的隔離級(jí)別,由底層數(shù)據(jù)庫引擎決定。READ_UNCOMMITTED:最低的隔離級(jí)別,允許讀取未提交的數(shù)據(jù)。該級(jí)別會(huì)導(dǎo)致“臟讀”、“不可重復(fù)讀”和“幻讀”等問題。READ_COMMITTED:只允許讀取已經(jīng)提交的數(shù)據(jù)。該級(jí)別可以避免“臟讀”,但可能會(huì)導(dǎo)致“不可重復(fù)讀”和“幻讀”等問題。REPEATABLE_READ:保證在同一個(gè)事務(wù)中多次讀取同一數(shù)據(jù)時(shí),該數(shù)據(jù)的值不會(huì)發(fā)生變化。該級(jí)別可以避免“臟讀”和“不可重復(fù)讀”,但可能會(huì)導(dǎo)致“幻讀”等問題。SERIALIZABLE:最高的隔離級(jí)別,強(qiáng)制事務(wù)串行執(zhí)行,避免了“臟讀”、“不可重復(fù)讀”和“幻讀”等問題。但是該級(jí)別會(huì)對(duì)性能產(chǎn)生較大的影響,因此一般不建議使用。
在選擇隔離級(jí)別時(shí),需要根據(jù)具體的業(yè)務(wù)需求來選擇合適的級(jí)別。一般來說,如果不需要在事務(wù)中讀取未提交的數(shù)據(jù),那么可以選擇READ_COMMITTED級(jí)別;如果需要避免“不可重復(fù)讀”問題,可以選擇REPEATABLE_READ級(jí)別;如果需要避免“幻讀”問題,可以選擇SERIALIZABLE級(jí)別。但是需要注意的是,隔離級(jí)別越高,事務(wù)的并發(fā)性越差,因此需要根據(jù)具體業(yè)務(wù)場(chǎng)景來權(quán)衡隔離級(jí)別和性能。
不可重復(fù)讀和幻讀的區(qū)別
不可重復(fù)讀和幻讀都是在并發(fā)讀寫數(shù)據(jù)時(shí)可能出現(xiàn)的問題。
不可重復(fù)讀指的是在一個(gè)事務(wù)中多次讀取同一數(shù)據(jù),但是由于其他事務(wù)的修改,導(dǎo)致兩次讀取的結(jié)果不一致。例如,事務(wù)A在讀取某個(gè)數(shù)據(jù)時(shí),事務(wù)B修改了該數(shù)據(jù)并提交,然后事務(wù)A再次讀取該數(shù)據(jù)時(shí),得到了不同的結(jié)果。
幻讀是指在一個(gè)事務(wù)中多次讀取同一范圍內(nèi)的數(shù)據(jù),但是由于其他事務(wù)的插入操作,導(dǎo)致兩次讀取的結(jié)果不一致。例如,事務(wù)A在讀取某個(gè)范圍內(nèi)的數(shù)據(jù)時(shí),事務(wù)B插入了一條數(shù)據(jù)并提交,然后事務(wù)A再次讀取該范圍內(nèi)的數(shù)據(jù)時(shí),得到了不同的結(jié)果。
不可重復(fù)讀和幻讀的區(qū)別在于,不可重復(fù)讀是在讀取同一數(shù)據(jù)時(shí)出現(xiàn)問題,而幻讀是在讀取同一范圍內(nèi)的數(shù)據(jù)時(shí)出現(xiàn)問題。解決不可重復(fù)讀的問題可以使用鎖機(jī)制或者提高事務(wù)的隔離級(jí)別,而解決幻讀的問題可以使用鎖機(jī)制或者使用更高的隔離級(jí)別,例如SERIALIZABLE級(jí)別。
rollbackFor屬性
在使用@Transactional注解進(jìn)行聲明式事務(wù)管理時(shí),可以通過rollbackFor屬性來指定哪些異常類型需要回滾事務(wù)。需要注意的是,rollbackFor屬性指定的異常類型必須是Throwable類型或其子類,并且必須包含在Spring事務(wù)拋出的異常類型之內(nèi)。如果指定的異常類型不正確或不在事務(wù)回滾的異常類型之內(nèi),可能會(huì)導(dǎo)致事務(wù)無法正確回滾或者回滾不完整的問題。
如果需要指定多個(gè)異常類型,可以使用數(shù)組的方式進(jìn)行指定,例如:
@Transactional(rollbackFor = {SQLException.class, IOException.class})
public void doSomething() {
// ...
}在上面的代碼中,指定了SQLException和IOException兩種異常類型需要回滾事務(wù)。默認(rèn)情況只有RuntimeException和Error會(huì)觸發(fā)事務(wù)回滾。
除了rollbackFor屬性外,@Transactional注解還有其他一些屬性可以用于指定事務(wù)的屬性和行為,包括propagation、isolation、timeout、readOnly等。需要根據(jù)具體的業(yè)務(wù)需求來選擇合適的屬性和行為,以保證事務(wù)的正確性和可靠性。
到此這篇關(guān)于一文搞清楚Spring事務(wù)的文章就介紹到這了,更多相關(guān)Java Spring事務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在IntelliJ IDEA中創(chuàng)建和運(yùn)行java/scala/spark程序的方法
這篇文章主要介紹了在IntelliJ IDEA中創(chuàng)建和運(yùn)行java/scala/spark程序的教程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05
MyBatis在注解上使用動(dòng)態(tài)SQL方式(@select使用if)
這篇文章主要介紹了MyBatis在注解上使用動(dòng)態(tài)SQL方式(@select使用if),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
SpringCloud?OpenFeign?服務(wù)調(diào)用傳遞?token的場(chǎng)景分析
這篇文章主要介紹了SpringCloud?OpenFeign?服務(wù)調(diào)用傳遞?token的場(chǎng)景分析,本篇文章簡(jiǎn)單介紹?OpenFeign?調(diào)用傳遞?header?,以及多線程環(huán)境下可能會(huì)出現(xiàn)的問題,其中涉及到?ThreadLocal?的相關(guān)知識(shí),需要的朋友可以參考下2022-07-07
RxJava2.x+ReTrofit2.x多線程下載文件的示例代碼
本篇文章主要介紹了RxJava2.x+ReTrofit2.x多線程下載文件的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-09-09
java多線程編程之Synchronized關(guān)鍵字詳解
這篇文章主要為大家詳細(xì)介紹了java多線程編程之Synchronized關(guān)鍵字,感興趣的朋友可以參考一下2016-05-05
SpringMVC4.3?HttpMessageConverter接口實(shí)現(xiàn)源碼分析
這篇文章主要為大家介紹了SpringMVC4.3?HttpMessageConverter接口實(shí)現(xiàn)源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09

