在瞭解@Transactional怎麼用以前咱們必需要先知道@Transactional有什麼用。下面舉個栗子:好比一個部門裏面有不少成員,這二者分別保存在部門表和成員表裏面,在刪除某個部門的時候,假設咱們默認刪除對應的成員。可是在執行的時候可能會出現這種狀況,咱們先刪除部門,再刪除成員,可是部門刪除成功了,刪除成員的時候出異常了。這時候咱們但願若是成員刪除失敗了,以前刪除的部門也取消刪除。這種場景就可使用@Transactional事物回滾。java
這裏之因此讓你們清楚checked異常和unchecked異常概念,是由於:
Spring使用聲明式事務處理,默認狀況下,若是被註解的數據庫操做方法中發生了unchecked異常,全部的數據庫操做將rollback;若是發生的異常是checked異常,默認狀況下數據庫操做仍是會提交的。mysql
checked異常:
表示無效,不是程序中能夠預測的。好比無效的用戶輸入,文件不存在,網絡或者數據庫連接錯誤。這些都是外在的緣由,都不是程序內部能夠控制的。
必須在代碼中顯式地處理。好比try-catch塊處理,或者給所在的方法加上throws說明,將異常拋到調用棧的上一層。
繼承自java.lang.Exception(java.lang.RuntimeException除外)。spring
unchecked異常:
表示錯誤,程序的邏輯錯誤。是RuntimeException的子類,好比IllegalArgumentException, NullPointerException和IllegalStateException。
不須要在代碼中顯式地捕獲unchecked異常作處理。
繼承自java.lang.RuntimeException(而java.lang.RuntimeException繼承自java.lang.Exception)。sql
看下面的異常結構圖或許層次感更加深些:數據庫
本實例採用的是eclipse+maven,maven只是做爲jar管理,即使不瞭解的maven的猿友也能夠讀懂。markdown
3.一、spring的配置文件網絡
裏面必須先配置tx名字空間以下:mybatis
爲了使用基於@Transactional的事務管理,須要在Spring中進行以下的配置:app
<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配置文件:eclipse
<?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.二、使用@Transactional,在添加用戶實現類方法加上註解
@Transactional(propagation=Propagation.REQUIRED)
public void addUser(User user) {
userDao.addUser(user);
String string = null;
if(string.equals("")) {
int i = 0;
}
}
上面的方法我故意讓其出現空指針異常,會事物回滾
3.三、運行單元測試類
@Test
public void addUserTest(){
User user = new User();
user.setUserName("luoguohui1");
user.setUserPassword("luoguohui1");
userService.addUser(user);
}
發現沒法插入進去,可是若是把@Transactional去掉,即代碼以下,雖然出現異常,可是數據庫中仍是有添加對應數據的:
3.四、源碼下載
本文的工程是在mybatis入門(含實例教程和源碼)的基礎上修改的,該文包含了數據庫腳本及工程搭建的詳細流程。
本文最終源碼下載:
http://download.csdn.net/detail/u013142781/9381184
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 註解,只能當你設置了基於接口的代理時它才生效。由於註解是 不能繼承 的,這就意味着若是正在使用基於類的代理時,那麼事務的設置將不能被基於類的代理所識別,並且對象也將不會被事務代理所包裝。