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