TCC源码解析-20190721

本文深入探讨TCC(Try/Confirm/Cancel)补偿性事务的实现,包括事务拦截器的运用,以及如何在confirm和cancel方法中确保幂等性。在TCC模式下,需在接口上添加特定注解,并实现try、confirm和cancel方法。确认与取消操作需检查订单状态,以避免不必要的更新,确保服务的幂等性。同时强调在分布式事务中不应过度捕获异常,允许异常向上抛出以便TCC进行后续处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
TCC柔性补偿性事务:尝试/ 确定/ 取消 三个接口都要我i们自己去实现

事务协调性不关心接口是怎么实现的,只会根据情况去调用,启动事务2调用尝试的接口,3提交或者失败调用取消接口。

1、需要提供分布式事务支持的接口上添加@Compensable

2、在对应的接口实现上添加@Compensable

3、在接口实现上添加confirmMethod、cancelMethod、transactionContextEditor

4、实现对应的confirmMethod、cancelMethod

注意: confirm方法和cancel方法必须与try方法在同一个类中.。根据类的反射找到方法invoke

5、主事务的业务都已经实现的差不多的时候才调用子事务

注意:

1、分布式事务里,不要轻易在业务层捕获所有异常,抛出异常才能被TCC感知到,然后回调。只捕获必要捕获的异常。

2、使用TCC-Transaction时,confirm和cancel的幂等性需要自己代码支持

思考:

为什么要在confirm、cancel里检查订单状态,而不直接修改为结束状态:

因为confirm确认的就是刚刚try方法里新增的一个订单。

###confirm、cancel里检查订单状态 "draft","paying","CONFIRMED"

先检查订单的状态,就算是取消只是update状态,使订单可查。痕迹可查。

-》 为了保证服务的幂等性

幂等性:使用相同参数对同一资源重复调用某个接口的结果与调用一次的结果相同

事务拦截器方法

package org.mengyun.tcctransaction.interceptor;
public class CompensableTransactionInterceptor {

    static final Logger logger = Logger.getLogger(CompensableTransactionInterceptor.class.getSimpleName());

    private TransactionManager transactionManager;

    private Set<Class<? extends Exception>> delayCancelExceptions;

    public void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }	
    //
    public void setDelayCancelExceptions(Set<Class<? extends Exception>> delayCancelExceptions) {
        this.delayCancelExceptions = delayCancelExceptions;
    }
	//事务拦截器通过AOP环绕到加了注解@Compensable的方法,环绕执行下面的方法
    public Object interceptCompensableMethod(ProceedingJoinPoint pjp) throws Throwable {
		//获取到加了注解的方法本身
        Method method = CompensableMethodUtils.getCompensableMethod(pjp);
		//获取到注解@Compensable自己本身 --> 获取注解的属性:取消的方法,确认的方法
        Compensable compensable = method.getAnnotation(Compensable.class);
        Propagation propagation = compensable.propagation();
        //获取事务上下文,RPC隐式参数中包含这个上下文
        TransactionContext transactionContext = FactoryBuilder.factoryOf(compensable.transactionContextEditor()).getInstance().get(pjp.getTarget(), method, pjp.getArgs());

        boolean asyncConfirm = compensable.asyncConfirm();

        boolean asyncCancel = compensable.asyncCancel();
	//判断是否有存在的事务队列
        boolean isTransactionActive = transactionManager.isTransactionActive();
		
        if (!TransactionUtils.isLegalTransactionContext(isTransactionActive, propagation, transactionContext)) {
            throw new SystemException("no active compensable transaction while propagation is mandatory for method " + method.getName());
        }

        MethodType methodType = CompensableMethodUtils.calculateMethodType(propagation, isTransactionActive, transactionContext);
		/*
		*这个方法判断:(!isTransactionActive && transactionContext == null)是否已经有事务了,事务上下文是否为空
		都满足说明式主事务,否则是分支事务
		*/
        switch (methodType) {
            case ROOT:
                return rootMethodProceed(pjp, asyncConfirm, asyncCancel);
            case PROVIDER:
                return providerMethodProceed(pjp, transactionContext, asyncConfirm, asyncCancel);
            default:
                return pjp.proceed();
        }
    }

	/**这里是主事务的操作
	开启事务
	注册,持久化事务
	然后判断是cancel,confirm
	清除事务
	*/
    private Object rootMethodProceed(ProceedingJoinPoint pjp, boolean asyncConfirm, boolean asyncCancel) throws Throwable {

        Object returnValue = null;

        Transaction transaction = null;

        try {
			事务为空那么就开启一个全新的事务
            transaction = transactionManager.begin();

            try {
            //继续后续操作
                returnValue = pjp.proceed();
            } catch (Throwable tryingException) {

                if (!isDelayCancelException(tryingException)) {
                   
                    logger.warn(String.format("compensable transaction trying failed. transaction content:%s", JSON.toJSONString(transaction)), tryingException);

                    transactionManager.rollback(asyncCancel);
                }

                throw tryingException;
            }

            transactionManager.commit(asyncConfirm);

        } finally {
            transactionManager.cleanAfterCompletion(transaction);
        }

        return returnValue;
    }

    private Object providerMethodProceed(ProceedingJoinPoint pjp, TransactionContext transactionContext, boolean asyncConfirm, boolean asyncCancel) throws Throwable {

        Transaction transaction = null;
        try {

            switch (TransactionStatus.valueOf(transactionContext.getStatus())) {
                case TRYING:
                    transaction = transactionManager.propagationNewBegin(transactionContext);
                    return pjp.proceed();
                case CONFIRMING:
                    try {
                        transaction = transactionManager.propagationExistBegin(transactionContext);
                        transactionManager.commit(asyncConfirm);
                    } catch (NoExistedTransactionException excepton) {
                        //the transaction has been commit,ignore it.
                    }
                    break;
                case CANCELLING:

                    try {
                        transaction = transactionManager.propagationExistBegin(transactionContext);
                        transactionManager.rollback(asyncCancel);
                    } catch (NoExistedTransactionException exception) {
                        //the transaction has been rollback,ignore it.
                    }
                    break;
            }

        } finally {
            transactionManager.cleanAfterCompletion(transaction);
        }

        Method method = ((MethodSignature) (pjp.getSignature())).getMethod();

        return ReflectionUtils.getNullValue(method.getReturnType());
    }

    private boolean isDelayCancelException(Throwable throwable) {

        if (delayCancelExceptions != null) {
            for (Class delayCancelException : delayCancelExceptions) {

                Throwable rootCause = ExceptionUtils.getRootCause(throwable);

                if (delayCancelException.isAssignableFrom(throwable.getClass())
                        || (rootCause != null && delayCancelException.isAssignableFrom(rootCause.getClass()))) {
                    return true;
                }
            }
        }

        return false;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值