使用lambda表達式優雅你的事務代碼


我們在實現業務邏輯時,經常會有這種需求:

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);



    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM