Spring中@Transactional事務回滾例項及原始碼
一、使用場景舉例
在瞭解@Transactional怎麼用之前我們必須要先知道@Transactional有什麼用。下面舉個例子:比如一個部門裡面有很多成員,這兩者分別儲存在部門表和成員表裡面,在刪除某個部門的時候,假設我們預設刪除對應的成員。但是在執行的時候可能會出現這種情況,我們先刪除部門,再刪除成員,但是部門刪除成功了,刪除成員的時候出異常了。這時候我們希望如果成員刪除失敗了,之前刪除的部門也取消刪除。這種場景就可以使用@Transactional事物回滾。
二、checked異常和unchecked異常
這裡之所以讓大家清楚checked異常和unchecked異常概念,是因為:
Spring使用宣告式事務處理,預設情況下,如果被註解的資料庫操作方法中發生了unchecked異常,所有的資料庫操作將rollback;如果發生的異常是checked異常,預設情況下資料庫操作還是會提交的。
checked異常:
表示無效,不是程式中可以預測的。比如無效的使用者輸入,檔案不存在,網路或者資料庫連結錯誤。這些都是外在的原因,都不是程式內部可以控制的。
必須在程式碼中顯式地處理。比如try-catch塊處理,或者給所在的方法加上throws說明,將異常拋到呼叫棧的上一層。
繼承自java.lang.Exception(java.lang.RuntimeException除外)。
unchecked異常:
表示錯誤,程式的邏輯錯誤。是RuntimeException的子類,比如IllegalArgumentException, NullPointerException和IllegalStateException。
不需要在程式碼中顯式地捕獲unchecked異常做處理。
繼承自java.lang.RuntimeException(而java.lang.RuntimeException繼承自java.lang.Exception)。
看下面的異常結構圖或許層次感更加深些:
三、@Transactional的使用例項
本例項採用的是Eclipse+maven,maven只是作為jar管理,即便不瞭解的maven的猿友也可以讀懂。
3.1、spring的配置檔案
裡面必須先配置tx名字空間如下:
為了使用基於@Transactional的事務管理,需要在Spring中進行如下的配置:
<bean id="appTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:annotation-driven proxy-target-class="false" transaction-manager="appTransactionManager" />
博主的整個spring配置檔案:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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-2.5.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 引入jdbc配置檔案 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:properties/*.properties</value> <!--要是有多個配置檔案,只需在這裡繼續新增即可 --> </list> </property> </bean> <!-- 配置資料來源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <!-- 不使用properties來配置 --> <!-- <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/learning" /> <property name="username" value="root" /> <property name="password" value="christmas258@" /> --> <!-- 使用properties來配置 --> <property name="driverClassName"> <value>${jdbc_driverClassName}</value> </property> <property name="url"> <value>${jdbc_url}</value> </property> <property name="username"> <value>${jdbc_username}</value> </property> <property name="password"> <value>${jdbc_password}</value> </property> </bean> <bean id="appTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:annotation-driven proxy-target-class="false" transaction-manager="appTransactionManager" /> <!-- 自動掃描了所有的XxxxMapper.xml對應的mapper介面檔案,這樣就不用一個一個手動配置Mpper的對映了,只要Mapper介面類和Mapper對映檔案對應起來就可以了。 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.luo.dao" /> </bean> <!-- 配置Mybatis的檔案 ,mapperLocations配置**Mapper.xml檔案位置,configLocation配置mybatis-config檔案位置--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations" value="classpath:mapper/*.xml"/> <property name="configLocation" value="classpath:mybatis/mybatis-config.xml" /> <!-- <property name="typeAliasesPackage" value="com.tiantian.ckeditor.model" /> --> </bean> <!-- 自動掃描註解的bean --> <context:component-scan base-package="com.luo.service" /> </beans>
3.2、使用@Transactional,在新增使用者實現類方法加上註解
@Transactional(propagation=Propagation.REQUIRED) public void addUser(User user) { userDao.addUser(user); String string = null; if(string.equals("")) { int i = 0; } }
上面的方法我故意讓其出現空指標異常,會事物回滾
3.3、執行單元測試類
@Test public void addUserTest(){ User user = new User(); user.setUserName("luoguohui1"); user.setUserPassword("luoguohui1"); userService.addUser(user); }
發現無法插入進去,但是如果把@Transactional去掉,即程式碼如下,雖然出現異常,但是資料庫中還是有新增對應資料的:
3.4、原始碼下載
本文的工程是在mybatis入門(含例項教程和原始碼)的基礎上修改的,該文包含了資料庫指令碼及工程搭建的詳細流程。
本文最終原始碼下載:
http://download.csdn.net/detail/u013142781/9381184
四、Spring中的@Transactional必須要了解的概念
Spring中的@Transactional基於動態代理的機制,提供了一種透明的事務管理機制,方便快捷解決在開發中碰到的問題。
一般使用是通過如下程式碼對方法或介面或類註釋:
@Transactional(propagation=Propagation.NOT_SUPPORTED)
Propagation支援7種不同的傳播機制:
REQUIRED:如果存在一個事務,則支援當前事務。如果沒有事務則開啟一個新的事務。
SUPPORTS: 如果存在一個事務,支援當前事務。如果沒有事務,則非事務的執行。但是對於事務同步的事務管理器,PROPAGATION_SUPPORTS與不使用事務有少許不同。
NOT_SUPPORTED:總是非事務地執行,並掛起任何存在的事務。
REQUIRESNEW:總是開啟一個新的事務。如果一個事務已經存在,則將這個存在的事務掛起。
MANDATORY:如果已經存在一個事務,支援當前事務。如果沒有一個活動的事務,則丟擲異常。
NEVER:總是非事務地執行,如果存在一個活動事務,則丟擲異常
NESTED:如果一個活動的事務存在,則執行在一個巢狀的事務中。如果沒有活動事務,則按REQUIRED屬性執行。
下面是一些需要注意的事項,必須必須必須要看,不然遇到各種坑別說博主沒有提醒你哦:
下面是一些需要注意的事項,必須必須必須要看,不然遇到各種坑別說博主沒有提醒你哦:
下面是一些需要注意的事項,必須必須必須要看,不然遇到各種坑別說博主沒有提醒你哦:
- 在需要事務管理的地方加@Transactional 註解。@Transactional 註解可以被應用於介面定義和介面方法、類定義和類的 public 方法上。
- @Transactional 註解只能應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 註解,它也不會報錯, 但是這個被註解的方法將不會展示已配置的事務設定。
- 注意僅僅 @Transactional 註解的出現不足於開啟事務行為,它僅僅 是一種後設資料。必須在配置檔案中使用配置元素,才真正開啟了事務行為。
- 通過 元素的 “proxy-target-class” 屬性值來控制是基於介面的還是基於類的代理被建立。如果 “proxy-target-class” 屬值被設定為 “true”,那麼基於類的代理將起作用(這時需要CGLIB庫cglib.jar在CLASSPATH中)。如果 “proxy-target-class” 屬值被設定為 “false” 或者這個屬性被省略,那麼標準的JDK基於介面的代理將起作用。
- Spring團隊建議在具體的類(或類的方法)上使用 @Transactional 註解,而不要使用在類所要實現的任何介面上。在介面上使用 @Transactional 註解,只能當你設定了基於介面的代理時它才生效。因為註解是 不能繼承 的,這就意味著如果正在使用基於類的代理時,那麼事務的設定將不能被基於類的代理所識別,而且物件也將不會被事務代理所包裝。
- @Transactional 的事務開啟 ,或者是基於介面的 或者是基於類的代理被建立。所以在同一個類中一個方法呼叫另一個方法有事務的方法,事務是不會起作用的。
相關文章
- 關於事務回滾註解@Transactional
- 《四 spring原始碼》spring的事務註解@Transactional 原理分析Spring原始碼
- Spring中@Transactional事務使用陷阱Spring
- Spring Data JPA中事務回滾意外RollbackExceptionSpringException
- Spring宣告式事務@Transactional使用Spring
- Spring事務管理(詳解+例項)Spring
- Spring事務不能回滾的深層次原因Spring
- Spring @Transactional 宣告式事務揭祕Spring
- 【Spring註解】事務註解@TransactionalSpring
- Spring原始碼剖析9:Spring事務原始碼剖析Spring原始碼
- Spring 事務原始碼解析Spring原始碼
- 【spring原始碼】十一、事務Spring原始碼
- Spring原始碼分析(六)SpringAOP例項及標籤的解析Spring原始碼
- Spring事務原始碼分析專題(一)JdbcTemplate使用及原始碼分析Spring原始碼JDBC
- Spring+Mybatis事務@Transactional註解timeout屬性作用過程原始碼淺層DebugSpringMyBatis原始碼
- Spring非同步Async和事務Transactional註解Spring非同步
- Oracle vs PostgreSQL,研發注意事項(3)- 事務回滾之UPDATE操作解析OracleSQL
- Spring事務原始碼解讀Spring原始碼
- 【spring原始碼學習】Spring @PostConstruct和@PreDestroy例項Spring原始碼Struct
- 編碼式事務管理使用例項
- spring事務增強,事務回滾如何判斷?希望在前端上有個提示Spring前端
- Spring原始碼剖析8:Spring事務概述Spring原始碼
- Spring 原始碼分析之 bean 例項化原理Spring原始碼Bean
- 【spring 原始碼】IOC 之bean例項的建立Spring原始碼Bean
- sqlserver遇到回滾事務的操作策略SQLServer
- Spring事務的介紹,以及基於註解@Transactional的宣告式事務Spring
- spring boot 顯示處理事務回滾Spring Boot
- Dubbo原始碼分析(一)Dubbo與Spring整合例項原始碼Spring
- Spring Bean 的例項化過程原始碼解析SpringBean原始碼
- MySQL實現事務的提交和回滾MySql
- 不能回滾的Redis事務還能用嗎Redis
- Java開啟事務(@Transactional)Java
- Spring 原始碼學習 - 單例bean的例項化過程Spring原始碼單例Bean
- spring原始碼解析 (七) 事務底層原始碼實現Spring原始碼
- spring事務管理原始碼分析(二)事務處理流程分析Spring原始碼
- Spring事務專題(四)Spring中事務的使用、抽象機制及模擬Spring事務實現Spring抽象
- 美化滾動條效果程式碼例項
- Spring程式設計式和宣告式事務例項講解Spring程式設計
- Spring Boot 事物回滾Spring Boot