Spring中的@Transactional事務注解


一、事務特性

@Transactional注解是用於事務控制的,需要知道事務的ACID特征:即原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)、持久性(Durability)。

事務是用來控制數據的ACID特性的,用於保證數據的正確性和完整性。

@Transactional注解有兩種使用方式:

(1)標注在類上面:當作用於類上時,該類的所有public方法將都具有該類型的事務屬性,同時,我們也可以在方法級別使用該標注來覆蓋類級別的定義。

(2)標注在方法上面:當作用於方法上時,只有當該方法發生了異常才會進行回滾,其他的方法不受影響。

在項目中使用,@Transactional(rollbackFor=Exception.class),如果類加了這個注解,那么這個類里面的方法拋出異常,就會回滾,數據庫里面的數據也會回滾。在@Transactional注解中如果不配置rollbackFor屬性,那么事物只會在遇到RuntimeException的時候才會回滾,加上rollbackFor=Exception.class,可以讓事物在遇到非運行時異常時也回滾。


二、事務傳播行為與隔離級別

@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)

(1)事物傳播行為介紹:

@Transactional(propagation=Propagation.REQUIRED) :如果有事務, 那么加入事務, 沒有的話新建一個(默認情況下)
@Transactional(propagation=Propagation.NOT_SUPPORTED) :容器不為這個方法開啟事務
@Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事務,都創建一個新的事務,原來的掛起,新的執行完畢后繼續執行老的事務
@Transactional(propagation=Propagation.MANDATORY) :必須在一個已有的事務中執行,否則拋出異常
@Transactional(propagation=Propagation.NEVER) :必須在一個沒有的事務中執行,否則拋出異常(與Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS) :如果其他bean調用這個方法,在其他bean中聲明事務那就用事務,如果其他bean沒有聲明事務,那就不用事務

(2)事物超時設置:

@Transactional(timeout=30) //默認是30秒

(3)事務隔離級別:

@Transactional(isolation = Isolation.READ_UNCOMMITTED):讀取未提交數據(會出現臟讀, 不可重復讀) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED):讀取已提交數據(會出現不可重復讀和幻讀)
@Transactional(isolation = Isolation.REPEATABLE_READ):可重復讀(會出現幻讀)
@Transactional(isolation = Isolation.SERIALIZABLE):串行化
    
MYSQL: 默認為REPEATABLE_READ級別
SQLSERVER: 默認為READ_COMMITTED  

臟讀 : 一個事務讀取到另一事務未提交的更新數據。
不可重復讀 : 在同一事務中,多次讀取同一數據返回的結果有所不同,即后續讀取可能讀到另一事務已提交的更新數據, 相反, "可重復讀"在同一事務中多次
讀取數據時能夠保證所讀數據一樣,即后續讀取不能讀到另一事務已提交的更新數據。
幻讀 : 一個事務讀到另一個事務已提交的insert數據。


三、spring支持編程式事務管理和聲明式事務管理兩種方式

(1)編程式事務管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對於編程式事務管理,spring推薦使用TransactionTemplate。
(2)聲明式事務管理建立在AOP之上的。其本質是對方法前后進行攔截,然后在目標方法開始之前創建或者加入一個事務,在執行完目標方法之后根據執行情況提交或者回滾事務。聲明式事務管理也有兩種常用的方式:一種是基於tx和aop名字空間的xml配置文件;另一種是基於@Transactional注解。顯然基於注解的方式更簡單易用,更清爽。
使用注解形式的方式使用事務需要在xml配置文件中配置如下信息

<!-- 服務事務管理 -->
<bean id="demoTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="demoDataSource"/>
</bean>
 <!-- 啟用事務注解 -->
<tx:annotation-driven transaction-manager="demoTransactionManager"/>

四、需要注意的幾點如下

(1)@Transactional 注解只能被應用到public方法上,對於其它非public的方法,如果標記了@Transactional也不會報錯,但方法沒有事務功能。
(2)用spring事務管理器,由spring來負責數據庫的打開、提交、回滾,默認遇到運行期異常(throw new RuntimeException("注釋");)會回滾,即遇到不受檢查(unchecked)的異常時執行回滾;而遇到需要捕獲的異常(throw new Exception("注釋");)不會回滾,即遇到受檢查的異常(就是非運行時拋出的異常,編譯器會檢查到的異常叫受檢異常)時,需要我們指定方式來讓事務回滾。如果要想所有異常都回滾,則要加上@Transactional( rollbackFor=Exception.class),
如果讓unchecked異常不回滾: @Transactional(notRollbackFor=RunTimeException.class)。如下代碼所示:

@Transactional(rollbackFor=Exception.class) //指定回滾,遇到異常Exception時回滾
public void methodName() {
   throw new Exception("注釋");
}
@Transactional(noRollbackFor=Exception.class)//指定不回滾,遇到運行期例外(throw new RuntimeException("注釋");)會回滾
public ItimDaoImpl getItemDaoImpl() {
   throw new RuntimeException("注釋");
}

(3)@Transactional 注解應該只被應用到public可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不會報錯, 但是這個被注解的方法將不具有事務功能。
(4)@Transactional 注解可以被應用於接口定義和接口方法、類定義和類的 public 方法上。然而,請注意僅僅 @Transactional 注解的出現不足於開啟事務行為,它僅僅是一種元數據,能夠被可以識別。上面的例子中,其實正是元素的出現開啟了事務行為。也就是說要有具體的bean出現時事務才會起作用。
(5)Spring團隊建議在具體的類(或類的方法)上使用@Transactional 注解,而不要使用在類所要實現的任何接口上。你當然可以在接口上使用 @Transactional 注解,但是這將只能當你設置了基於接口的代理時它才生效。因為注解是不能繼承的,這就意味着如果你正在使用基於類的代理時,那么事務的設置將不能被基於類的代理所識別。因此,請接受Spring團隊的建議,必須接受啊!


五、@Transactional注解所具有的屬性

屬性 類型 描述
value String 可選的限定描述符,指定使用的事務管理器
propagation enum: Propagation 可選的事務傳播行為設置
isolation enum: Isolation 可選的事務隔離級別設置
readOnly boolean 讀寫或只讀事務,默認讀寫
timeout int (in seconds granularity) 事務超時時間設置
rollbackFor Class對象數組,必須繼承自Throwable 導致事務回滾的異常類數組
rollbackForClassName 類名數組,必須繼承自Throwable 導致事務回滾的異常類名字數組
noRollbackFor Class對象數組,必須繼承自Throwable 不會導致事務回滾的異常類數組
noRollbackForClassName 類名數組,必須繼承自Throwable 不會導致事務回滾的異常類名字數組

六、事務可能導致鎖表

事務有可能導致鎖表,從而導致查詢操作超時。鎖表的原因是多個事務同時操作某一張表。

mysql事務鎖表參考博文: https://blog.csdn.net/wo541075754/article/details/50717842 (mysql事務鎖表導致查詢超時)

mysql中主要是注意以下三張表:

select * from information_schema.INNODB_LOCKS;
select  * from information_schema.INNODB_LOCK_WAITS;
select * from information_schema.INNODB_TRX;

參考博文:
(1) https://www.cnblogs.com/clwydjgs/p/9317849.html (Spring中的@Transactional(rollbackFor = Exception.class)屬性詳解)
(2) https://www.cnblogs.com/caoyc/p/5632963.html (事物注解方式: @Transactional)
(3) https://www.cnblogs.com/jasonboren/p/11361971.html (mysql事務特性)
(4) https://www.cnblogs.com/jasonboren/p/13366130.html (Java 異常)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM