spring事物配置,宣告式事務管理和基於@Transactional註解的使用
事物管理對於企業應用來說是至關重要的,好使出現異常情況,它也可以保證資料的一致性。
spring支援程式設計式事務管理和宣告式事務管理兩種方式。
程式設計式事務管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對於程式設計式事務管理,spring推薦使用TransactionTemplate。
宣告式事務管理建立在AOP之上的。其本質是對方法前後進行攔截,然後在目標方法開始之前建立或者加入一個事務,在執行完目標方法之後根據執行情況提交或者回滾事務。宣告式事務最大的優點就是不需要通過程式設計的方式管理事務,這樣就不需要在業務邏輯程式碼中摻雜事務管理的程式碼,只需在配置檔案中做相關的事務規則宣告(或通過基於@Transactional註解的方式),便可以將事務規則應用到業務邏輯中。
顯然宣告式事務管理要優於程式設計式事務管理,這正是spring倡導的非侵入式的開發方式。宣告式事務管理使業務程式碼不受汙染,一個普通的POJO物件,只要加上註解就可以獲得完全的事務支援。和程式設計式事務相比,宣告式事務唯一不足地方是,後者的最細粒度只能作用到方法級別,無法做到像程式設計式事務那樣可以作用到程式碼塊級別。但是即便有這樣的需求,也存在很多變通的方法,比如,可以將需要進行事務管理的程式碼塊獨立為方法等等。
宣告式事務管理也有兩種常用的方式,一種是基於tx和aop名字空間的xml配置檔案,另一種就是基於@Transactional註解。顯然基於註解的方式更簡單易用,更清爽。
spring事務特性
spring所有的事務管理策略類都繼承自org.springframework.transaction.PlatformTransactionManager介面
其中TransactionDefinition介面定義以下特性:
事務隔離級別
隔離級別是指若干個併發的事務之間的隔離程度。TransactionDefinition 介面中定義了五個表示隔離級別的常量:
- TransactionDefinition.ISOLATION_DEFAULT:這是預設值,表示使用底層資料庫的預設隔離級別。對大部分資料庫而言,通常這值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED:該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的資料。該級別不能防止髒讀,不可重複讀和幻讀,因此很少使用該隔離級別。比如PostgreSQL實際上並沒有此級別。
- TransactionDefinition.ISOLATION_READ_COMMITTED:該隔離級別表示一個事務只能讀取另一個事務已經提交的資料。該級別可以防止髒讀,這也是大多數情況下的推薦值。
- TransactionDefinition.ISOLATION_REPEATABLE_READ:該隔離級別表示一個事務在整個過程中可以多次重複執行某個查詢,並且每次返回的記錄都相同。該級別可以防止髒讀和不可重複讀。
- TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止髒讀、不可重複讀以及幻讀。但是這將嚴重影響程式的效能。通常情況下也不會用到該級別。
事務傳播行為
所謂事務的傳播行為是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為。在TransactionDefinition定義中包括瞭如下幾個表示傳播行為的常量:
- TransactionDefinition.PROPAGATION_REQUIRED:如果當前存在事務,則加入該事務;如果當前沒有事務,則建立一個新的事務。這是預設值。
- TransactionDefinition.PROPAGATION_REQUIRES_NEW:建立一個新的事務,如果當前存在事務,則把當前事務掛起。
- TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續執行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式執行,如果當前存在事務,則把當前事務掛起。
- TransactionDefinition.PROPAGATION_NEVER:以非事務方式執行,如果當前存在事務,則丟擲異常。
- TransactionDefinition.PROPAGATION_MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則丟擲異常。
- TransactionDefinition.PROPAGATION_NESTED:如果當前存在事務,則建立一個事務作為當前事務的巢狀事務來執行;如果當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。
事務超時
所謂事務超時,就是指一個事務所允許執行的最長時間,如果超過該時間限制但事務還沒有完成,則自動回滾事務。在 TransactionDefinition 中以 int 的值來表示超時時間,其單位是秒。
預設設定為底層事務系統的超時值,如果底層資料庫事務系統沒有設定超時值,那麼就是none,沒有超時限制。
事務只讀屬性
“只讀事務”並不是一個強制選項,它只是一個“暗示”,提示資料庫驅動程式和資料庫系統,這個事務並不包含更改資料的操作,那麼JDBC驅動程式和資料庫就有可能根據這種情況對該事務進行一些特定的優化,比方說不安排相應的資料庫鎖,以減輕事務對資料庫的壓力,畢竟事務也是要消耗資料庫的資源的。
但是你非要在“只讀事務”裡面修改資料,也並非不可以,只不過對於資料一致性的保護不像“讀寫事務”那樣保險而已。
因此,“只讀事務”僅僅是一個效能優化的推薦配置而已,並非強制你要這樣做不可
spring事務回滾規則
指示spring事務管理器回滾一個事務的推薦方法是在當前事務的上下文內丟擲異常。spring事務管理器會捕捉任何未處理的異常,然後依據規則決定是否回滾丟擲異常的事務。
預設配置下,spring只有在丟擲的異常為執行時unchecked異常時才回滾該事務,也就是丟擲的異常為RuntimeException的子類(Errors也會導致事務回滾),而丟擲checked異常則不會導致事務回滾。可以明確的配置在丟擲那些異常時回滾事務,包括checked異常。也可以明確定義那些異常丟擲時不回滾事務。還可以程式設計性的通過setRollbackOnly()方法來指示一個事務必須回滾,在呼叫完setRollbackOnly()後你所能執行的唯一操作就是回滾。
- myBatis為例 基於註解的宣告式事務管理配置@Transactional
spring.xml
- <span style="background-color: rgb(255, 255, 255);"><span style="background-color: rgb(255, 204, 153);"><!-- mybatis config -->
- <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
- <property name="dataSource" ref="dataSource" />
- <property name="configLocation">
- <value>classpath:mybatis-config.xml</value>
- </property>
- </bean>
- <!-- mybatis mappers, scanned automatically -->
- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
- <property name="basePackage">
- <value>
- com.baobao.persistence.test
- </value>
- </property>
- <property name="sqlSessionFactory" ref="sqlSessionFactory" />
- </bean>
- <!-- 配置spring的PlatformTransactionManager,名字為預設值 -->
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!-- 開啟事務控制的註解支援 -->
- <tx:annotation-driven transaction-manager="transactionManager"/></span></span>
- <span style="background-color: rgb(255, 255, 255);"><span style="background-color: rgb(255, 204, 153);">xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"</span></span>
MyBatis自動參與到spring事務管理中,無需額外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的資料來源與DataSourceTransactionManager引用的資料來源一致即可,否則事務管理會不起作用。
@Transactional註解
@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 | 不會導致事務回滾的異常類名字陣列 |
用法
@Transactional 可以作用於介面、介面方法、類以及類方法上。當作用於類上時,該類的所有 public 方法將都具有該型別的事務屬性,同時,我們也可以在方法級別使用該標註來覆蓋類級別的定義。
雖然 @Transactional 註解可以作用於介面、介面方法、類以及類方法上,但是 Spring 建議不要在介面或者介面方法上使用該註解,因為這隻有在使用基於介面的代理時它才會生效。另外, @Transactional 註解應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。如果你在 protected、private 或者預設可見性的方法上使用 @Transactional 註解,這將被忽略,也不會丟擲任何異常。
預設情況下,只有來自外部的方法呼叫才會被AOP代理捕獲,也就是,類內部方法呼叫本類內部的其他方法並不會引起事務行為,即使被呼叫方法使用@Transactional註解進行修飾。
- @Autowired
- private MyBatisDao dao;
- @Transactional
- @Override
- public void insert(Test test) {
- dao.insert(test);
- throw new RuntimeException("test");//丟擲unchecked異常,觸發事物,回滾
- }
- @Transactional(noRollbackFor=RuntimeException.class)
- @Override
- public void insert(Test test) {
- dao.insert(test);
- //丟擲unchecked異常,觸發事物,noRollbackFor=RuntimeException.class,不回滾
- throw new RuntimeException("test");
- }
類,當作用於類上時,該類的所有 public 方法將都具有該型別的事務屬性
- @Transactional
- public class MyBatisServiceImpl implements MyBatisService {
- @Autowired
- private MyBatisDao dao;
- @Override
- public void insert(Test test) {
- dao.insert(test);
- //丟擲unchecked異常,觸發事物,回滾
- throw new RuntimeException("test");
- }
propagation=Propagation.NOT_SUPPORTED
- @Transactional(propagation=Propagation.NOT_SUPPORTED)
- @Override
- public void insert(Test test) {
- //事物傳播行為是PROPAGATION_NOT_SUPPORTED,以非事務方式執行,不會存入資料庫
- dao.insert(test);
- }
- myBatis為例 基於註解的宣告式事務管理配置,xml配置
主要為aop切面配置,只看xml就可以了
- <!-- 事物切面配置 -->
- <tx:advice id="advice" transaction-manager="transactionManager">
- <tx:attributes>
- <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
- <tx:method name="insert" propagation="REQUIRED" read-only="false"/>
- </tx:attributes>
- </tx:advice>
- <aop:config>
- <aop:pointcut id="testService" expression="execution (* com.baobao.service.MyBatisService.*(..))"/>
- <aop:advisor advice-ref="advice" pointcut-ref="testService"/>
- </aop:config>
相關文章
- Spring事務的介紹,以及基於註解@Transactional的宣告式事務Spring
- Spring宣告式事務@Transactional使用Spring
- Spring @Transactional 宣告式事務揭祕Spring
- spring宣告式事務管理配置Spring
- 【Spring註解】事務註解@TransactionalSpring
- Spring非同步Async和事務Transactional註解Spring非同步
- Spring的事務管理(二)宣告式事務管理Spring
- @Transactional註解管理事務和手動提交事務
- spring基於註解配置實現事務控制Spring
- 關於事務回滾註解@Transactional
- 《四 spring原始碼》spring的事務註解@Transactional 原理分析Spring原始碼
- Spring筆記(4) - Spring的程式設計式事務和宣告式事務詳解Spring筆記程式設計
- 五(二)、spring 宣告式事務xml配置SpringXML
- 為什麼有人不推薦使用spring官方推薦的@Transactional宣告式註解Spring
- Spring中@Transactional事務使用陷阱Spring
- 三 Spring 宣告式事務Spring
- Spring-宣告式事務Spring
- Spring宣告式事務控制Spring
- Spring程式設計式和宣告式事務例項講解Spring程式設計
- Spring基於註解的aop配置Spring
- Spring基於註解的IoC配置Spring
- Spring Cloud OpenFeign:基於Ribbon和Hystrix的宣告式服務呼叫SpringCloud
- 深刻理解Spring宣告式事務Spring
- 事務註解(@Transactional)引起的資料覆蓋故障
- Spring宣告式事務控制原理之宣告式事務的重要元件在AOP中的應用Spring元件
- Spring @Transactional註解淺談Spring
- 分散式鎖和spring事務管理分散式Spring
- JavaEE(12)Spring整合Mybaits、宣告式事務JavaSpringAI
- Springboot資料庫事務處理——Spring宣告式事務Spring Boot資料庫
- Spring宣告式事務的兩種實現方式Spring
- 基於註解的方式使用spring-integration-redis分散式鎖SpringRedis分散式
- Spring宣告式事務純xml模式回顧SpringXML模式
- Spring(使用註解配置)Spring
- @Transactional 註解下,事務失效的多種場景
- Spring+Mybatis事務@Transactional註解timeout屬性作用過程原始碼淺層DebugSpringMyBatis原始碼
- 筆記53-Spring jdbcTemplate&宣告式事務筆記SpringJDBC
- 使用 Spring Transactional 註釋的最佳方式 - Vlad MihalceaSpring
- Spring管理的@Configuration註解使用Spring