我們在實現業務邏輯時,經常會有這種需求:
1、在當前事務A中開啟新事務B,事務B中發生異常不可以回滾A,事務B成功執行后返回事務B的返回值;
2、在當前事務A中開啟新事務B,事務B中發生異常要求回滾A,事務B成功執行后返回事務B的返回值;
3、在當前事務A中開啟新事務B,事務B中發生異常不可以回滾A,事務B成功執行后不需要返回;
4、在當前事務A中開啟新事務B,事務B中發生異常要求回滾A,事務B成功執行后不需要返回;
5、注冊后置事務B,即當前事務A成功提交后才會執行事務B,事務B異常的話不拋出,只打印異常日志;
6、注冊后置事務B,即當前事務A異常時執行事務B,事務B異常的話不拋出,只打印異常日志;
一、配置事務模版
<!--事務模版
1.標志REQUIRES_NEW會新開啟事務,外層事務異常外部事務會會館,不會回滾內部事務的提交
2.標志REQUIRES_NEW的內部事務的異常,內部事務會回滾,外部事務也會回滾-->
<bean id="transactionTemplateNew" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRES_NEW"/>
</bean>
二、定義接口
/** * @author zhaojiatao * @date 2019-07-14 */ public interface ICommonTransactionService { /** * 開啟一個新事務來執行函數,有返回值;與外部事務互相隔離,發生異常只回滾本事務,不會互相影響 * @param action * @param <T> * @urn */ <T> T newTransactionExecuteAndReturnWithOutThrowable(Supplier<T> action); /** * 開啟一個新事務來執行函數,有返回值;內部事務發生異常時會向外拋出異常,內部事務和外部事務均回滾 * @param action * @param <T> * @urn */ <T> T newTransactionExecuteAndReturnThrowable(Supplier<T> action) throws Exception; /** * 開啟一個新事務來執行函數,無返回值;與外部事務互相隔離,發生異常只回滾本事務,不會互相影響 * @param f */ void newTransactionRunVoidWithOutThrowable(Runnable f); /** * 開啟一個新事務來執行函數,無返回值;內部事務發生異常時會向外拋出異常,內部事務和外部事務均回滾 * @param f */ void newTransactionRunVoidThrowable(Runnable f) throws Exception; /** * 如果當前存在事務,則等當前事務提交后,回頭來開啟一個新事務執行,如果內部捕捉異常,不往外拋出;如果外部事務提交前外部事物異常,則此函數不會被執行 * https://docs.spring.io/spring/docs/1.2.7/javadoc-api/org/springframework/transaction/support/TransactionSynchronizationAdapter.html * @param f */ void registerTransactionAfterCommitNoThrowable(Runnable f); /** * 當前事務提交或者回滾后執行 Invoked after transaction commit/rollback * https://docs.spring.io/spring/docs/1.2.7/javadoc-api/org/springframework/transaction/support/TransactionSynchronizationAdapter.html * @param f */ void registerTransactionAfterRollBackNoThrowable(Runnable f); }
三、接口實現
/** * @author zhaojiatao * @date 2019-07-14 */ @Slf4j @Service("commonTransactionService") public class CommonTransactionServiceImpl implements ICommonTransactionService { @Autowired @Qualifier("transactionTemplateNew") TransactionTemplate transactionTemplateNew; @Override public <T> T newTransactionExecuteAndReturnWithOutThrowable(Supplier<T> action) { //執行帶有返回值<Object>的事務管理 return transactionTemplateNew.execute(transactionStatus-> { try { return action.get(); } catch (Exception e) { log.error("newTransactionExecuteAndReturnNoThrowable發生異常",e); //回滾 transactionStatus.setRollbackOnly(); return null; } }); } @Override public <T> T newTransactionExecuteAndReturnThrowable(Supplier<T> action) { //執行帶有返回值<Object>的事務管理 return transactionTemplateNew.execute(transactionStatus-> { try { return action.get(); } catch (Exception e) { log.error("newTransactionExecuteAndReturnNoThrowable發生異常",e); //回滾 transactionStatus.setRollbackOnly(); throw e; } }); } @Override public void newTransactionRunVoidWithOutThrowable(Runnable f) { //執行無返回值的事務管理 transactionTemplateNew.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { try { //業務代碼 f.run(); } catch (Exception e){ log.error("newTransactionRunVoidNoThrowable發生異常",e); //回滾 transactionStatus.setRollbackOnly(); } } }); } @Override public void newTransactionRunVoidThrowable(Runnable f) { //執行無返回值的事務管理 transactionTemplateNew.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { try { //業務代碼 f.run(); } catch (Exception e){ log.error("newTransactionRunVoidNoThrowable發生異常",e); //回滾 transactionStatus.setRollbackOnly(); throw e; } } }); } @Override public void registerTransactionAfterCommitNoThrowable(Runnable f) { try{ if (TransactionSynchronizationManager.isActualTransactionActive()) { TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCommit() { f.run(); } }); } else { f.run(); } }catch (Exception e){ log.error("執行后置事務發生異常",e); } } @Override public void registerTransactionAfterRollBackNoThrowable(Runnable f) { try{ if (TransactionSynchronizationManager.isActualTransactionActive()) { TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCompletion(int status) { log.error("執行事務回滾后置事務,status={}",status); f.run(); } }); } else { f.run(); } }catch (Exception e){ log.error("當前事務回滾后置事務發生異常",e); } } }
四、調用
@Test @Transactional(rollbackFor = Exception.class) public void commonTransactionServiceTest() throws Exception { //1、newTransactionExecute 開啟新事務 有返回值 String result=commonTransactionService.newTransactionExecuteAndReturnWithOutThrowable( ()->{ QueryObj queryObj = new QueryObj(); queryObj.setQuerydo(new OrderDO()); queryObj.addQueryParam(new QueryParam("id = #{id}", "347")); OrderDO orderDO = orderDAO.querySingle(queryObj); return JSON.toJSONString(orderDO); } ); log.info(result); //2、newTransactionRun 開啟新事務 無返回值 commonTransactionService.newTransactionRunVoidWithOutThrowable( ()->{ QueryObj queryObj = new QueryObj(); queryObj.setQuerydo(new OrderDO()); queryObj.addQueryParam(new QueryParam("id = #{id}", "347")); OrderDO orderDO = orderDAO.querySingle(queryObj); log.info(JSON.toJSONString(orderDO)); } ); int[] ids=new int[]{0}; //3、在新事務中insert數據 commonTransactionService.newTransactionRunVoidWithOutThrowable( ()->{ OrderDO orderDO=new OrderDO(); orderDO.setId(350L); orderDO.setOrderCode("350350"); orderDO.setCustomerId(81L); orderDO.setBusinessModel(LoanOrderBusinessModelEnum.SELF_SECOND_CAR_ICBC_DIRECT.getCode()); ids[0]=orderDAO.create(orderDO); log.info( ids[0]+""); //只回滾內部事務,不回滾外部事務 System.out.println(1/0); } ); //4、在外部事務提交后執行的后置新事務insert數據 commonTransactionService.registerTransactionAfterCommitNoThrowable( ()->{ OrderDO orderDO=new OrderDO(); orderDO.setId(351L); orderDO.setOrderCode("351351"); orderDO.setCustomerId(81L); orderDO.setBusinessModel(LoanOrderBusinessModelEnum.SELF_SECOND_CAR_ICBC_DIRECT.getCode()); ids[0]=orderDAO.create(orderDO); log.info( ids[0]+""); } ); //5、在外部事務中insert數據 if(true){ OrderDO orderDO=new OrderDO(); orderDO.setId(352L); orderDO.setOrderCode("352352"); orderDO.setCustomerId(81L); orderDO.setBusinessModel(LoanOrderBusinessModelEnum.SELF_SECOND_CAR_ICBC_DIRECT.getCode()); ids[0]=orderDAO.create(orderDO); log.info( ids[0]+""); } //6、在新事務中插入數據並異常 commonTransactionService.newTransactionRunVoidThrowable( ()->{ OrderDO orderDO=new OrderDO(); orderDO.setId(353L); orderDO.setOrderCode("353353"); orderDO.setCustomerId(81L); orderDO.setBusinessModel(LoanOrderBusinessModelEnum.SELF_SECOND_CAR_ICBC_DIRECT.getCode()); ids[0]=orderDAO.create(orderDO); log.info( ids[0]+""); System.out.println(1/0); } ); //注意驗證這個異常是無法回滾commonTransactionService.newTransactionRun的 //注意驗證這個異常會導致commonTransactionService.registerTransactionAfterCommitNoThrowable無法執行,因為事務沒有提交 // System.out.println(1/0); System.out.println(1); }
