PROPAGATION_REQUIRED 若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中html
PROPAGATION_REQUIRES_NEW 每個受影響的事務做用域都使用徹底 獨立的事務.物理上的事務就不一樣了而且能夠獨立的提交或者回滾, 外部事物不會影響到內部事務的回滾 狀態java
PROPAGATION_NESTED 事務嵌套 子事務是父事務的一部分,父事務失敗則所有回滾,若是子事務失敗,則回滾到進入子事務以前的狀態spring
官網好像只列出了這幾個,可是不少博客都說有9種,不過咱們大部分都用的Required級別,其它的就不深究了,若是須要進一步瞭解可參考 https://my.oschina.net/dongli...數據庫
理解聲明式事務實現機制
註解事務的最基本是利用了spring的aop實現,調用者調用的實則是目標類的代理類,代理類有事務的攔截器Interceptor, TransactionInterceptor 來實現對應的事務處理express
xml配置方式apache
<!-- 事務化配置 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <!-- 事務語義... --> <tx:attributes> <!-- 全部用'get'開頭的方法都是隻讀的 --> <tx:method name="get*" read-only="true"/> <!-- 其餘的方法使用默認的事務配置(看下面) --> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- 定義切面配置 --> <aop:config> <!-- FooService 下的全部方法--> <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/> </aop:config> <!-- DataSource數據源配置 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/> <property name="username" value="scott"/> <property name="password" value="tiger"/> </bean> <!-- 聲明事務管理器實現 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
tx-method配置項說明編程
配置項 | 是否必須 | 默認值 | 描述 |
---|---|---|---|
name | 是 | ||
propagation | 否 | REQUIRED | 事務傳播行爲,參考上文描述 |
isolation | 否 | DEFAULT | 隔離級別 default使用數據庫默認的事務隔離級別 |
timeout | 否 | -1 | 事務超時時間 單位 秒 |
read-only | 否 | false | 事務級別是否只讀 |
rollback-for | 否 | ----- | 指定回滾異常類型 |
no-rollback-for | 否 | ----- | 指定什麼異常類型不回滾 |
isolation 可選值
DEFAULT 使用當前數據庫默認的事務界別
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ 可重複讀
SERIALIZABLEapi
註解方式(經常使用)mybatis
配置的方式是採用通配符的方式進行事務切入,不夠靈活,在實際開發中註解的方式用的較多,配置可參考下面oracle
<!-- 數據源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/> <property name="username" value="scott"/> <property name="password" value="tiger"/> </bean> <!-- 使用註解配置的事務行爲生效 --> <tx:annotation-driven transaction-manager="txManager"/> <!--事務管理器--> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--開啓事務註解配置 --> <tx:annotation-driven transaction-manager="txManager"/>
須要事務的方法加上註解便可
//註解加到類上,則該類裏全部public方法啓用事務 //註解加在方法上,則只有方法啓用事務 @Transactional public class DefaultFooService implements FooService { Foo getFoo(String fooName); Foo getFoo(String fooName, String barName); void insertFoo(Foo foo); void updateFoo(Foo foo); }
方法可見性和@Transactional
當使用代理時, 你應該只給public可見性的方法添加@Transactional註解. 若是你給protected, private或者包訪問的方法添加了@Transactional註解, 不會產生錯誤, 可是事務不生效. 若是你須要給非公開的方法添加註解能夠參考其它文檔,此處不作概述
多數據源,多事務
<!-- 同上,不一樣的dataSource配置不一樣的txManager --> <tx:annotation-driven transaction-manager="txManager"/> <tx:annotation-driven transaction-manager="txManager1"/> <tx:annotation-driven transaction-manager="txManager2"/>
//名字和事務管理器同名便可 @Transactional("txManager1") public class DefaultFooService implements FooService { Foo getFoo(String fooName); Foo getFoo(String fooName, String barName); void insertFoo(Foo foo); void updateFoo(Foo foo); }
也能夠給txManager加上別名
<!--事務管理器--> <bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <qualifier value="order"/> <property name="dataSource" ref="dataSource"/> </bean> <bean id="txManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <qualifier value="account"/> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="txManager1"/> <tx:annotation-driven transaction-manager="txManager2"/>
//名字和事務管理器的qualifier相同便可 @Transactional("order") public class DefaultFooService implements FooService { Foo getFoo(String fooName); Foo getFoo(String fooName, String barName); void insertFoo(Foo foo); void updateFoo(Foo foo); }
*使用註解的方式,注意下面這種情形,防止事務不生效
1.不要對本身要進行事務控制的代碼進行try catch,spring的事務觸發是執行體出現異常,若是本身的程序catch住了異常,spring事務管理器覺得執行成功,回滾不生效
//錯誤示例 @Transactional public void update2(String name){ try { jdbcTemplate.execute("UPDATE t_menua SET mname='"+name+"' WHERE mid=106 "); } catch (DataAccessException e) { e.printStackTrace(); } }
//錯誤案例 @Transactional public void update2(String name){ jdbcTemplate.execute("UPDATE t_menua SET mname='"+name+"' WHERE mid=106 "); } public void update3(String name) { this.update2(name); throw new RuntimeException(); }
調用堆棧以下
//事務生效 @Transactional public void update2(String name){ jdbcTemplate.execute("UPDATE t_menua SET mname='"+name+"' WHERE mid=106 "); } @Transactional public void update3(String name) { this.update2(name); throw new RuntimeException(); }
調用堆棧以下
你們對比能夠發現,第一種的執行棧裏壓根就沒有事務攔截器,因此事務沒有生效
spring 配置
<!-- dataSource 配置同上--> <!-- 事務管理器 配置同上 管理器名字 txManage--> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" > <property name="transactionManager" ref="txManage" /> </bean>
java代碼
public class LocalDataService { /** * 編程式事務模板 */ @Resource private TransactionTemplate transactionTemplate; /** * dao層執行體,能夠是hibernate,mybatis等其它db框架 */ @Resource private JdbcTemplate jdbcTemplate; /** * 修改數據 */ public void update(final String name){ transactionTemplate.execute(new TransactionCallback<Integer>() { public Integer doInTransaction(TransactionStatus transactionStatus) { jdbcTemplate.execute("UPDATE t_menua SET mname='"+name+"' WHERE mid=106 "); return 1; } }); throw new RuntimeException(); } }
transactionTemplate 官方有兩種
TransactionTemplate
PlatformTransactionManager
Spring通常都推薦使用TransactionTemplate來進行編程式事務管理. 第二種方式有點相似於使用JTA的 UserTransaction接口
參考文檔
spring中文文檔 http://spring.cndocs.tk/trans...