spring的@Transactional注解用法解讀
概述
事務(wù)管理對(duì)于企業(yè)應(yīng)用來(lái)說(shuō)是至關(guān)重要的,即使出現(xiàn)異常情況,它也可以保證數(shù)據(jù)的一致性。
Spring Framework對(duì)事務(wù)管理提供了一致的抽象,其特點(diǎn)如下:
為不同的事務(wù)API提供一致的編程模型,比如JTA(Java Transaction API), JDBC, Hibernate, JPA(Java Persistence API和JDO(Java Data Objects)
支持聲明式事務(wù)管理,特別是基于注解的聲明式事務(wù)管理,簡(jiǎn)單易用
提供比其他事務(wù)API如JTA更簡(jiǎn)單的編程式事務(wù)管理API
與spring數(shù)據(jù)訪問(wèn)抽象的完美集成
事務(wù)管理方式
spring支持編程式事務(wù)管理和聲明式事務(wù)管理兩種方式。
編程式事務(wù)管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對(duì)于編程式事務(wù)管理,spring推薦使用TransactionTemplate。
聲明式事務(wù)管理建立在AOP之上的。其本質(zhì)是對(duì)方法前后進(jìn)行攔截,然后在目標(biāo)方法開始之前創(chuàng)建或者加入一個(gè)事務(wù),在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況提交或者回滾事務(wù)。聲明式事務(wù)最大的優(yōu)點(diǎn)就是不需要通過(guò)編程的方式管理事務(wù),這樣就不需要在業(yè)務(wù)邏輯代碼中摻雜事務(wù)管理的代碼,只需在配置文件中做相關(guān)的事務(wù)規(guī)則聲明(或通過(guò)基于@Transactional注解的方式),便可以將事務(wù)規(guī)則應(yīng)用到業(yè)務(wù)邏輯中。
顯然聲明式事務(wù)管理要優(yōu)于編程式事務(wù)管理,這正是spring倡導(dǎo)的非侵入式的開發(fā)方式。聲明式事務(wù)管理使業(yè)務(wù)代碼不受污染,一個(gè)普通的POJO對(duì)象,只要加上注解就可以獲得完全的事務(wù)支持。和編程式事務(wù)相比,聲明式事務(wù)唯一不足地方是,后者的最細(xì)粒度只能作用到方法級(jí)別,無(wú)法做到像編程式事務(wù)那樣可以作用到代碼塊級(jí)別。但是即便有這樣的需求,也存在很多變通的方法,比如,可以將需要進(jìn)行事務(wù)管理的代碼塊獨(dú)立為方法等等。
聲明式事務(wù)管理也有兩種常用的方式,一種是基于tx和aop名字空間的xml配置文件,另一種就是基于@Transactional注解。顯然基于注解的方式更簡(jiǎn)單易用,更清爽。
自動(dòng)提交(AutoCommit)與連接關(guān)閉時(shí)的是否自動(dòng)提交
自動(dòng)提交
默認(rèn)情況下,數(shù)據(jù)庫(kù)處于自動(dòng)提交模式。每一條語(yǔ)句處于一個(gè)單獨(dú)的事務(wù)中,在這條語(yǔ)句執(zhí)行完畢時(shí),如果執(zhí)行成功則隱式的提交事務(wù),如果
執(zhí)行失敗則隱式的回滾事務(wù)。
對(duì)于正常的事務(wù)管理,是一組相關(guān)的操作處于一個(gè)事務(wù)之中,因此必須關(guān)閉數(shù)據(jù)庫(kù)的自動(dòng)提交模式。不過(guò),這個(gè)我們不用擔(dān)心,spring會(huì)將底層連接的自動(dòng)提交特性設(shè)置為false。
org/springframework/jdbc/datasource/DataSourceTransactionManager.java
// switch to manual commit if necessary. this is very expensive in some jdbc drivers, // so we don't want to do it unnecessarily (for example if we've explicitly // configured the connection pool to set it already). if (con.getautocommit()) { txobject.setmustrestoreautocommit(true); if (logger.isdebugenabled()) { logger.debug("switching jdbc connection [" + con + "] to manual commit"); } con.setautocommit(false); }
有些數(shù)據(jù)連接池提供了關(guān)閉事務(wù)自動(dòng)提交的設(shè)置,最好在設(shè)置連接池時(shí)就將其關(guān)閉。但C3P0沒(méi)有提供這一特性,只能依靠spring來(lái)設(shè)置。
因?yàn)镴DBC規(guī)范規(guī)定,當(dāng)連接對(duì)象建立時(shí)應(yīng)該處于自動(dòng)提交模式,這是跨DBMS的缺省值,如果需要,必須顯式的關(guān)閉自動(dòng)提交。C3P0遵守這一規(guī)范,讓客戶代碼來(lái)顯式的設(shè)置需要的提交模式。
連接關(guān)閉時(shí)的是否自動(dòng)提交
當(dāng)一個(gè)連接關(guān)閉時(shí),如果有未提交的事務(wù)應(yīng)該如何處理?JDBC規(guī)范沒(méi)有提及,C3P0默認(rèn)的策略是回滾任何未提交的事務(wù)。這是一個(gè)正確的策略,但JDBC驅(qū)動(dòng)提供商之間對(duì)此問(wèn)題并沒(méi)有達(dá)成一致。
C3P0的autoCommitOnClose屬性默認(rèn)是false,沒(méi)有十分必要不要?jiǎng)铀??;蛘呖梢燥@式的設(shè)置此屬性為false,這樣會(huì)更明確。
基于注解的聲明式事務(wù)管理配置
spring-servlet.xml
<!-- transaction support--> <!-- PlatformTransactionMnager --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- enable transaction annotation support --> <tx:annotation-driven transaction-manager="txManager" />
還要在spring-servlet.xml中添加tx名字空間
... xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" ... http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd ...
MyBatis自動(dòng)參與到spring事務(wù)管理中,無(wú)需額外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的數(shù)據(jù)源與DataSourceTransactionManager引用的數(shù)據(jù)源一致即可,否則事務(wù)管理會(huì)不起作用。
另外需要下載依賴包aopalliance.jar放置到WEB-INF/lib目錄下。否則spring初始化時(shí)會(huì)報(bào)異常
java.lang.NoClassDefFoundError: org/aopalliance/intercept/MethodInterceptor
spring事務(wù)特性
spring所有的事務(wù)管理策略類都繼承自org.springframework.transaction.PlatformTransactionManager接口
public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
其中TransactionDefinition接口定義以下特性:
事務(wù)隔離級(jí)別
隔離級(jí)別是指若干個(gè)并發(fā)的事務(wù)之間的隔離程度。TransactionDefinition 接口中定義了五個(gè)表示隔離級(jí)別的常量:
TransactionDefinition.ISOLATION_DEFAULT:這是默認(rèn)值,表示使用底層數(shù)據(jù)庫(kù)的默認(rèn)隔離級(jí)別。對(duì)大部分?jǐn)?shù)據(jù)庫(kù)而言,通常這值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:該隔離級(jí)別表示一個(gè)事務(wù)可以讀取另一個(gè)事務(wù)修改但還沒(méi)有提交的數(shù)據(jù)。該級(jí)別不能防止臟讀,不可重復(fù)讀和幻讀,因此很少使用該隔離級(jí)別。比如PostgreSQL實(shí)際上并沒(méi)有此級(jí)別。
TransactionDefinition.ISOLATION_READ_COMMITTED:該隔離級(jí)別表示一個(gè)事務(wù)只能讀取另一個(gè)事務(wù)已經(jīng)提交的數(shù)據(jù)。該級(jí)別可以防止臟讀,這也是大多數(shù)情況下的推薦值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:該隔離級(jí)別表示一個(gè)事務(wù)在整個(gè)過(guò)程中可以多次重復(fù)執(zhí)行某個(gè)查詢,并且每次返回的記錄都相同。該級(jí)別可以防止臟讀和不可重復(fù)讀。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事務(wù)依次逐個(gè)執(zhí)行,這樣事務(wù)之間就完全不可能產(chǎn)生干擾,也就是說(shuō),該級(jí)別可以防止臟讀、不可重復(fù)讀以及幻讀。但是這將嚴(yán)重影響程序的性能。通常情況下也不會(huì)用到該級(jí)別。
事務(wù)傳播行為
所謂事務(wù)的傳播行為是指,如果在開始當(dāng)前事務(wù)之前,一個(gè)事務(wù)上下文已經(jīng)存在,此時(shí)有若干選項(xiàng)可以指定一個(gè)事務(wù)性方法的執(zhí)行行為。在TransactionDefinition定義中包括了如下幾個(gè)表示傳播行為的常量:
TransactionDefinition.PROPAGATION_REQUIRED:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。這是默認(rèn)值。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:創(chuàng)建一個(gè)新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
TransactionDefinition.PROPAGATION_NEVER:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常。
TransactionDefinition.PROPAGATION_MANDATORY:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則拋出異常。
TransactionDefinition.PROPAGATION_NESTED:如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)行;如果當(dāng)前沒(méi)有事務(wù),則該取值等價(jià)于TransactionDefinition.PROPAGATION_REQUIRED。
事務(wù)超時(shí)
所謂事務(wù)超時(shí),就是指一個(gè)事務(wù)所允許執(zhí)行的最長(zhǎng)時(shí)間,如果超過(guò)該時(shí)間限制但事務(wù)還沒(méi)有完成,則自動(dòng)回滾事務(wù)。在 TransactionDefinition 中以 int 的值來(lái)表示超時(shí)時(shí)間,其單位是秒。
默認(rèn)設(shè)置為底層事務(wù)系統(tǒng)的超時(shí)值,如果底層數(shù)據(jù)庫(kù)事務(wù)系統(tǒng)沒(méi)有設(shè)置超時(shí)值,那么就是none,沒(méi)有超時(shí)限制。
事務(wù)只讀屬性
只讀事務(wù)用于客戶代碼只讀但不修改數(shù)據(jù)的情形,只讀事務(wù)用于特定情景下的優(yōu)化,比如使用Hibernate的時(shí)候。
默認(rèn)為讀寫事務(wù)。
spring事務(wù)回滾規(guī)則
指示spring事務(wù)管理器回滾一個(gè)事務(wù)的推薦方法是在當(dāng)前事務(wù)的上下文內(nèi)拋出異常。spring事務(wù)管理器會(huì)捕捉任何未處理的異常,然后依據(jù)規(guī)則決定是否回滾拋出異常的事務(wù)。
默認(rèn)配置下,spring只有在拋出的異常為運(yùn)行時(shí)unchecked異常時(shí)才回滾該事務(wù),也就是拋出的異常為RuntimeException的子類(Errors也會(huì)導(dǎo)致事務(wù)回滾),而拋出checked異常則不會(huì)導(dǎo)致事務(wù)回滾。
可以明確的配置在拋出那些異常時(shí)回滾事務(wù),包括checked異常。也可以明確定義那些異常拋出時(shí)不回滾事務(wù)。
還可以編程性的通過(guò)setRollbackOnly()方法來(lái)指示一個(gè)事務(wù)必須回滾,在調(diào)用完setRollbackOnly()后你所能執(zhí)行的唯一操作就是回滾。
@Transactional注解
@Transactional屬性
屬性 | 類型 | 描述 |
---|---|---|
value | String | 可選的限定描述符,指定使用的事務(wù)管理器 |
propagation | enum: Propagation | 可選的事務(wù)傳播行為設(shè)置 |
isolation | enum: Isolation | 可選的事務(wù)隔離級(jí)別設(shè)置 |
readOnly | boolean | 讀寫或只讀事務(wù),默認(rèn)讀寫 |
timeout | int (in seconds granularity) | 事務(wù)超時(shí)時(shí)間設(shè)置 |
rollbackFor | Class對(duì)象數(shù)組,必須繼承自Throwable | 導(dǎo)致事務(wù)回滾的異常類數(shù)組 |
rollbackForClassName | 類名數(shù)組,必須繼承自Throwable | 導(dǎo)致事務(wù)回滾的異常類名字?jǐn)?shù)組 |
noRollbackFor | Class對(duì)象數(shù)組,必須繼承自Throwable | 不會(huì)導(dǎo)致事務(wù)回滾的異常類數(shù)組 |
noRollbackForClassName | 類名數(shù)組,必須繼承自Throwable | 不會(huì)導(dǎo)致事務(wù)回滾的異常類名字?jǐn)?shù)組 |
用法
@Transactional 可以作用于接口、接口方法、類以及類方法上。當(dāng)作用于類上時(shí),該類的所有 public 方法將都具有該類型的事務(wù)屬性,同時(shí),我們也可以在方法級(jí)別使用該標(biāo)注來(lái)覆蓋類級(jí)別的定義。
雖然 @Transactional 注解可以作用于接口、接口方法、類以及類方法上,但是 Spring 建議不要在接口或者接口方法上使用該注解,因?yàn)檫@只有在使用基于接口的代理時(shí)它才會(huì)生效。另外, @Transactional 注解應(yīng)該只被應(yīng)用到 public 方法上,這是由 Spring AOP 的本質(zhì)決定的。如果你在 protected、private 或者默認(rèn)可見性的方法上使用 @Transactional 注解,這將被忽略,也不會(huì)拋出任何異常。
默認(rèn)情況下,只有來(lái)自外部的方法調(diào)用才會(huì)被AOP代理捕獲,也就是,類內(nèi)部方法調(diào)用本類內(nèi)部的其他方法并不會(huì)引起事務(wù)行為,即使被調(diào)用方法使用@Transactional注解進(jìn)行修飾。
@Transactional(readOnly = true) public class DefaultFooService implements FooService { public Foo getFoo(String fooName) { // do something } // these settings have precedence for this method //方法上注解屬性會(huì)覆蓋類注解上的相同屬性 @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) public void updateFoo(Foo foo) { // do something } }
總結(jié)
以上就是本文關(guān)于spring的@Transactional注解用法解讀的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
- spring中12種@Transactional的失效場(chǎng)景(小結(jié))
- Spring中@Transactional用法詳細(xì)介紹
- springboot中事務(wù)管理@Transactional的注意事項(xiàng)與使用場(chǎng)景
- Spring @Transactional工作原理詳解
- Spring @Transactional注解失效解決方案
- spring @Transactional 無(wú)效的解決方案
- spring中@Transactional?注解失效的原因及解決辦法
- Spring事務(wù)@Transactional注解四種不生效案例場(chǎng)景分析
- spring中@Transactional注解和事務(wù)的實(shí)戰(zhàn)
相關(guān)文章
Java實(shí)現(xiàn)文件分片上傳接口的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Java語(yǔ)言實(shí)現(xiàn)文件分片上傳的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2022-07-07Java實(shí)現(xiàn)統(tǒng)計(jì)字符串出現(xiàn)的次數(shù)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)統(tǒng)計(jì)字符串出現(xiàn)的次數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10java獲取登錄者IP和登錄時(shí)間的兩種實(shí)現(xiàn)代碼詳解
這篇文章主要介紹了java獲取登錄者IP和登錄時(shí)間的實(shí)現(xiàn)代碼,本文通過(guò)兩種結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07詳解SpringBoot優(yōu)雅編碼之Lombok加持
這篇文章主要介紹了詳解SpringBoot優(yōu)雅編碼之Lombok加持,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06Java將Date日期類型字段轉(zhuǎn)換成json字符串的方法
這篇文章主要給大家介紹了關(guān)于Java將Date日期類型字段轉(zhuǎn)換成json字符串的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02Java?C++題解leetcode902最大為N的數(shù)字組合數(shù)位DP
這篇文章主要為大家介紹了Java?C++題解leetcode902最大為N的數(shù)字組合數(shù)位DP,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10IDEA中程序包Org.Springframework.Boot不存在問(wèn)題及解決
這篇文章主要介紹了IDEA中程序包Org.Springframework.Boot不存在問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07