有這種業務需求:java
一次業務分三個步驟完成spring
步驟1:insert table1 成功後,執行update table2 成功後,執行update table3
執行邏輯確定以下數據庫
int success1 = insert table1; if(success1 == 1) { int success2 = update table2; if(success2 == 1) { int success3 = update table3; if(success3 == 1) { //成功 }else { //失敗3 } }else { //失敗2 } }else { //失敗1 }
如今,存在這種狀況,假設步驟1和步驟2都成功了,express
執行步驟3的時候,返回0,即success3 == 0,可是又沒有報異常,這個時候事物就不會回滾,即步驟1插入成功,步驟2也更新成功了,步驟3更新失敗,這時候返回給前臺的信息是此次操做失敗,可是步驟1和步驟2仍然影響了數據庫。app
解決辦法以下ui
方法0:自動回滾,controller層捕獲異常,且處理異常,加tryprototype
事物配置在service層,所以service層中的方法不作異常捕獲,而是放在上層(即controller層)捕獲、處理。代理
//controller層 try{ //事物層方法 }catch{ //異常處理 }
方法1:自動回滾,加try catchcode
事物配置在service層,service層的方法捕獲異常,而後跑出異常,讓aop去執行回滾
事務
//service層實現方法 try{ insert table1; update table2; update table3; }catch(Exception e) { //拋出異常 throw new RuntimeException(); }
方法2:手動回滾,我目前就採用這種方法
事物配置在service層,service層的方法捕獲異常,處理異常(即執行該事物回滾操做)。
//service層實現方法 import org.springframework.transaction.interceptor.TransactionAspectSupport; //手動回滾 int success1 = insert table1; if(success1 == 1) { int success2 = update table2; if(success2 == 1) { int success3 = update table3; if(success3 == 1) { //成功 }else { //失敗3 //手動回滾 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }else { //失敗2 //手動回滾 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }else { //失敗1 //手動回滾 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); }
spring的事物配置以下
<!-- ========================================分隔線========================================= --> <!-- 配置Spring的事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 攔截器方式配置事物 --> <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="append*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="modify*" propagation="REQUIRED" /> <tx:method name="edit*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="repair" propagation="REQUIRED" /> <tx:method name="delAndRepair" propagation="REQUIRED" /> <tx:method name="regist*" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" /> <tx:method name="find*" propagation="SUPPORTS" /> <tx:method name="load*" propagation="SUPPORTS" /> <tx:method name="search*" propagation="SUPPORTS" /> <tx:method name="datagrid*" propagation="SUPPORTS" /> <tx:method name="*" propagation="SUPPORTS" /> </tx:attributes> </tx:advice> <aop:config> <!-- 匹配com.readygo.zbhealth.service.impl這個類下面的全部方法--> <aop:pointcut id="transactionPointcut" expression="execution(* com.readygo.zbhealth.service.impl.*Impl.*(..))" /> <!--把事務控制在Service層--> <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" /> </aop:config> <!-- 配置druid監控spring jdbc --> <bean id="druid-stat-interceptor" class="com.alibaba.druid.support.spring.stat.DruidStatInterceptor"> </bean> <bean id="druid-stat-pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype"> <property name="patterns"> <list> <value>com.readygo.zbhealth.service.impl.*</value> </list> </property> </bean> <aop:config> <aop:advisor advice-ref="druid-stat-interceptor" pointcut-ref="druid-stat-pointcut" /> </aop:config>
spring aop 異常捕獲原理
被攔截的方法須要顯式的拋出異常,且該異常沒有被處理,這樣aop代理才能捕獲到方法的異常,才能進行回滾;默認狀況下,aop只能捕獲runtimeexception()異常。
方法0
在controll層捕獲service層方法異常,controller層處理異常。
方法1
service捕獲service層方法異常,service層拋出異常,自動回滾。
方法2
service層捕獲service層方法異常,service層方法本身處理異常,手動回滾。這種方式上層不須要處理異常。