TCC,基于业务层面的事物定义,粒度完全由业务自己控制,本质上还是补偿的思路,它把事物运行过程分为try-confirm-cancel阶段,每个阶段逻辑由业务代码控制

业务活动管理器控制业务活动的一致性,它登记业务活动中的操作,并在业务活动提交时确认所有的TCC型操作的confirm操作,在业务活动取消时调用所有TCC型操作的cancel操作

与2PC的区别,没有单独的准备阶段,try操作兼备资源操作与准备能力,try操作可以灵活选择业务资源锁定的粒度;

关于柔性事物,看下支付宝这个介绍:https://www.zhihu.com/question/31813039

支付宝所说的柔性事务分为:两阶段型、补偿型、异步确保型、最大努力通知型几种。

两阶段 - XA/JTA/JTS;

补偿型 - TCC, 在一个长事物中,一个由两台服务器一起参与的事物,服务器A发起事物,B参与事物,但B处理时间很长,如果按照ACDI的原则,要保持事物的隔离性一致性,服务器A中发起的事物中使用到的事物资源将会被锁定,不允许其他应用访问到事物过程中的中间结果,直到整个事物被提交或者回滚,就会导致事物A中的资源被长期锁定,系统的可用性将不可接受;对于这种情况,所以诞生了补偿型事物,服务器A的事物如果执行顺利,则事物A先行提交,如果B也执行顺利,则B也提交,整个事物完成,如果B失败,则B本身回滚,这时A已经被提交,所以需要执行一个补偿操作,将A已经提交的事物执行一个反操作,恢复到未执行前事物A的状态,这样牺牲了一定的隔离性和一致性,但提高了整体事物的可用性

异步确保型 - 将一些同步阻塞的事物操作变为异步操作,避免对数据库事物的争用

最大努力型 - 交易的消息通知;

1. 主动方在业务处理的同一个本地事务中,记录消息数据,提交后发送消息到被动方,成功后删除消息,消息补偿系统定期找到未成功发送的消息,补偿发送

2. 业务处理服务在业务事务提交前,向实时消息服务请求发送消息,实时消息服务只记录消息数据而不真正发送(未提交前,已存待发送),业务处理服务在业务事务提交后,向实时消息服务确认发送(提交后确认发送,回滚取消发送),消息状态确认系统定期找到未确认发送或回滚的消息,反向询问业务系统消息状态,业务系统根据消息ID或消息内容确认该消息是否有效

文章下评论中截取

柔性就是不依靠数据库本身的事物,通常是根据业务特性,在分库分表,业务单元化部署或跨不同业务场景下,通过业务层2PC时候校正,消息队列等方式,达到服务之间数据一致性的方式。利用业务上对于事物过程中不一致的容忍度,找到让事物最终一致的方法,寻求一种技术能力和业务诉求平衡的方法;

比如AB转账;A减少和B增加,刚性事物是要求这两个动作同时发生;柔性事物是先A减少,再B增加,分布式环境中难以保证同事增加和减少,但是只要保证A减少后,B能在可接受的范围内,最终加上,可就能最终一致;

事物拦截器 -> 事物管理器 -> 事物存储器 事物恢复job

From博文:

TCC-Trasaction有两个拦截器对@Compensable AOP切面(参与者try方法)进行拦截,透明化对参与者confirm/cancel方法调用,

可补偿事物拦截器,在try阶段,对事物的发起传播,在confirm/cancel阶段,对事物的提交或回滚,在远程调用服务的参与者时,会通过序列化方式传递事物给远程参与者

资源协调者拦截器,在try阶段,添加参与者到事物中,当事物上下文不存在时进行创建

如何在定义后拦截并实现事物管理?@Compensable(confirmMethod = "confirmMakePayment", cancelMethod = "cancelMakePayment", asyncConfirm = true)

首先定义一个注解

  1. package org.mengyun.tcctransaction.api;
  2.  
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. import java.lang.reflect.Method;
  8.  
  9. /**
  10. * Created by changmingxie on 10/25/15.
  11. */
  12. @Retention(RetentionPolicy.RUNTIME)
  13. @Target({ElementType.METHOD})
  14. public @interface Compensable {
  15.  
  16. public Propagation propagation() default Propagation.REQUIRED;
  17.  
  18. public String confirmMethod() default "";
  19.  
  20. public String cancelMethod() default "";
  21.  
  22. public Class<? extends TransactionContextEditor> transactionContextEditor() default DefaultTransactionContextEditor.class;
  23.  
  24. public boolean asyncConfirm() default false;
  25.  
  26. public boolean asyncCancel() default false;
  27.  
  28. class NullableTransactionContextEditor implements TransactionContextEditor {
  29.  
  30. @Override
  31. public TransactionContext get(Object target, Method method, Object[] args) {
  32. return null;
  33. }
  34.  
  35. @Override
  36. public void set(TransactionContext transactionContext, Object target, Method method, Object[] args) {
  37.  
  38. }
  39. }
  40.  
  41. class DefaultTransactionContextEditor implements TransactionContextEditor {
  42. @Override
  43. public TransactionContext get(Object target, Method method, Object[] args) {
  44. int position = getTransactionContextParamPosition(method.getParameterTypes());
  45. if (position >= 0) {
  46. return (TransactionContext) args[position];
  47. }
  48. return null;
  49. }
  50.  
  51. @Override
  52. public void set(TransactionContext transactionContext, Object target, Method method, Object[] args) {
  53.  
  54. int position = getTransactionContextParamPosition(method.getParameterTypes());
  55. if (position >= 0) {
  56. args[position] = transactionContext;
  57. }
  58. }
  59.  
  60. public static int getTransactionContextParamPosition(Class<?>[] parameterTypes) {
  61. int position = -1;
  62. for (int i = 0; i < parameterTypes.length; i++) {
  63. if (parameterTypes[i].equals(org.mengyun.tcctransaction.api.TransactionContext.class)) {
  64. position = i;
  65. break;
  66. }
  67. }
  68. return position;
  69. }
  70.  
  71. public static TransactionContext getTransactionContextFromArgs(Object[] args) {
  72. TransactionContext transactionContext = null;
  73. for (Object arg : args) {
  74. if (arg != null && org.mengyun.tcctransaction.api.TransactionContext.class.isAssignableFrom(arg.getClass())) {
  75. transactionContext = (org.mengyun.tcctransaction.api.TransactionContext) arg;
  76. }
  77. }
  78. return transactionContext;
  79. }
  80. }
  81. }

定义拦截器

  1. package org.mengyun.tcctransaction.interceptor;
  2.  
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.Around;
  5. import org.aspectj.lang.annotation.Aspect;
  6. import org.aspectj.lang.annotation.Pointcut;
  7.  
  8. /**
  9. * Created by changmingxie on 10/30/15.
  10. */
  11. @Aspect
  12. public abstract class CompensableTransactionAspect {
  13.  
  14. private CompensableTransactionInterceptor compensableTransactionInterceptor;
  15.  
  16. public void setCompensableTransactionInterceptor(CompensableTransactionInterceptor compensableTransactionInterceptor) {
  17. this.compensableTransactionInterceptor = compensableTransactionInterceptor;
  18. }
  19.  
  20. @Pointcut("@annotation(org.mengyun.tcctransaction.api.Compensable)")
  21. public void compensableService() {
  22.  
  23. }
  24.  
  25. @Around("compensableService()")
  26. public Object interceptCompensableMethod(ProceedingJoinPoint pjp) throws Throwable {
  27. return compensableTransactionInterceptor.interceptCompensableMethod(pjp);
  28. }
  29. public abstract int getOrder();
  30. }

具体实现

  1. package org.mengyun.tcctransaction.spring;
  2.  
  3. import org.aspectj.lang.annotation.Aspect;
  4. import org.mengyun.tcctransaction.TransactionManager;
  5. import org.mengyun.tcctransaction.interceptor.CompensableTransactionAspect;
  6. import org.mengyun.tcctransaction.interceptor.CompensableTransactionInterceptor;
  7. import org.mengyun.tcctransaction.support.TransactionConfigurator;
  8. import org.springframework.core.Ordered;
  9.  
  10. /**
  11. * Created by changmingxie on 10/30/15.
  12. */
  13. @Aspect
  14. public class ConfigurableTransactionAspect extends CompensableTransactionAspect implements Ordered {
  15. private TransactionConfigurator transactionConfigurator;
  16. public void init() {
  17. TransactionManager transactionManager = transactionConfigurator.getTransactionManager();
  18. CompensableTransactionInterceptor compensableTransactionInterceptor = new CompensableTransactionInterceptor();
  19. compensableTransactionInterceptor.setTransactionManager(transactionManager);
  20. compensableTransactionInterceptor.setDelayCancelExceptions(transactionConfigurator.getRecoverConfig().getDelayCancelExceptions());
  21. this.setCompensableTransactionInterceptor(compensableTransactionInterceptor);
  22. }
  23.  
  24. @Override
  25. public int getOrder() {
  26. return Ordered.HIGHEST_PRECEDENCE;
  27. }
  28.  
  29. public void setTransactionConfigurator(TransactionConfigurator transactionConfigurator) {
  30. this.transactionConfigurator = transactionConfigurator;
  31. }
  32. }

定义补偿拦截器,拿到定义了的方法,生成对应的事物操作,事物管理器调用和交互

  1. package org.mengyun.tcctransaction.interceptor;
  2.  
  3. import com.alibaba.fastjson.JSON;
  4. import org.apache.commons.lang3.exception.ExceptionUtils;
  5. import org.apache.log4j.Logger;
  6. import org.aspectj.lang.ProceedingJoinPoint;
  7. import org.aspectj.lang.reflect.MethodSignature;
  8. import org.mengyun.tcctransaction.NoExistedTransactionException;
  9. import org.mengyun.tcctransaction.SystemException;
  10. import org.mengyun.tcctransaction.Transaction;
  11. import org.mengyun.tcctransaction.TransactionManager;
  12. import org.mengyun.tcctransaction.api.Compensable;
  13. import org.mengyun.tcctransaction.api.Propagation;
  14. import org.mengyun.tcctransaction.api.TransactionContext;
  15. import org.mengyun.tcctransaction.api.TransactionStatus;
  16. import org.mengyun.tcctransaction.common.MethodType;
  17. import org.mengyun.tcctransaction.support.FactoryBuilder;
  18. import org.mengyun.tcctransaction.utils.CompensableMethodUtils;
  19. import org.mengyun.tcctransaction.utils.ReflectionUtils;
  20. import org.mengyun.tcctransaction.utils.TransactionUtils;
  21.  
  22. import java.lang.reflect.Method;
  23. import java.util.Set;
  24.  
  25. /**
  26. * Created by changmingxie on 10/30/15.
  27. */
  28. public class CompensableTransactionInterceptor {
  29.  
  30. static final Logger logger = Logger.getLogger(CompensableTransactionInterceptor.class.getSimpleName());
  31.  
  32. private TransactionManager transactionManager;
  33.  
  34. private Set<Class<? extends Exception>> delayCancelExceptions;
  35.  
  36. public void setTransactionManager(TransactionManager transactionManager) {
  37. this.transactionManager = transactionManager;
  38. }
  39.  
  40. public void setDelayCancelExceptions(Set<Class<? extends Exception>> delayCancelExceptions) {
  41. this.delayCancelExceptions = delayCancelExceptions;
  42. }
  43.  
  44. public Object interceptCompensableMethod(ProceedingJoinPoint pjp) throws Throwable {
  45. Method method = CompensableMethodUtils.getCompensableMethod(pjp);
  46. Compensable compensable = method.getAnnotation(Compensable.class);
  47. Propagation propagation = compensable.propagation();
  48. TransactionContext transactionContext = FactoryBuilder.factoryOf(compensable.transactionContextEditor()).getInstance().get(pjp.getTarget(), method, pjp.getArgs());
  49. boolean asyncConfirm = compensable.asyncConfirm();
  50. boolean asyncCancel = compensable.asyncCancel();
  51. boolean isTransactionActive = transactionManager.isTransactionActive();
  52. if (!TransactionUtils.isLegalTransactionContext(isTransactionActive, propagation, transactionContext)) {
  53. throw new SystemException("no active compensable transaction while propagation is mandatory for method " + method.getName());
  54. }
  55. MethodType methodType = CompensableMethodUtils.calculateMethodType(propagation, isTransactionActive, transactionContext);
  56. switch (methodType) {
  57. case ROOT:
  58. return rootMethodProceed(pjp, asyncConfirm, asyncCancel);
  59. case PROVIDER:
  60. return providerMethodProceed(pjp, transactionContext, asyncConfirm, asyncCancel);
  61. default:
  62. return pjp.proceed();
  63. }
  64. }
  65.  
  66. private Object rootMethodProceed(ProceedingJoinPoint pjp, boolean asyncConfirm, boolean asyncCancel) throws Throwable {
  67. Object returnValue = null;
  68. Transaction transaction = null;
  69. try {
  70. transaction = transactionManager.begin();
  71. try {
  72. returnValue = pjp.proceed();
  73. } catch (Throwable tryingException) {
  74. if (!isDelayCancelException(tryingException)) {
  75. logger.warn(String.format("compensable transaction trying failed. transaction content:%s", JSON.toJSONString(transaction)), tryingException);
  76. transactionManager.rollback(asyncCancel);
  77. }
  78. throw tryingException;
  79. }
  80. transactionManager.commit(asyncConfirm);
  81. } finally {
  82. transactionManager.cleanAfterCompletion(transaction);
  83. }
  84. return returnValue;
  85. }
  86.  
  87. private Object providerMethodProceed(ProceedingJoinPoint pjp, TransactionContext transactionContext, boolean asyncConfirm, boolean asyncCancel) throws Throwable {
  88. Transaction transaction = null;
  89. try {
  90. switch (TransactionStatus.valueOf(transactionContext.getStatus())) {
  91. case TRYING:
  92. transaction = transactionManager.propagationNewBegin(transactionContext);
  93. return pjp.proceed();
  94. case CONFIRMING:
  95. try {
  96. transaction = transactionManager.propagationExistBegin(transactionContext);
  97. transactionManager.commit(asyncConfirm);
  98. } catch (NoExistedTransactionException excepton) {
  99. //the transaction has been commit,ignore it.
  100. }
  101. break;
  102. case CANCELLING:
  103.  
  104. try {
  105. transaction = transactionManager.propagationExistBegin(transactionContext);
  106. transactionManager.rollback(asyncCancel);
  107. } catch (NoExistedTransactionException exception) {
  108. //the transaction has been rollback,ignore it.
  109. }
  110. break;
  111. }
  112. } finally {
  113. transactionManager.cleanAfterCompletion(transaction);
  114. }
  115. Method method = ((MethodSignature) (pjp.getSignature())).getMethod();
  116. return ReflectionUtils.getNullValue(method.getReturnType());
  117. }
  118.  
  119. private boolean isDelayCancelException(Throwable throwable) {
  120. if (delayCancelExceptions != null) {
  121. for (Class delayCancelException : delayCancelExceptions) {
  122. Throwable rootCause = ExceptionUtils.getRootCause(throwable);
  123. if (delayCancelException.isAssignableFrom(throwable.getClass())
  124. || (rootCause != null && delayCancelException.isAssignableFrom(rootCause.getClass()))) {
  125. return true;
  126. }
  127. }
  128. }
  129. return false;
  130. }
  131. }

资源拦截器

  1. package org.mengyun.tcctransaction.interceptor;
  2.  
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.Around;
  5. import org.aspectj.lang.annotation.Aspect;
  6. import org.aspectj.lang.annotation.Pointcut;
  7.  
  8. /**
  9. * Created by changmingxie on 11/8/15.
  10. */
  11. @Aspect
  12. public abstract class ResourceCoordinatorAspect {
  13. private ResourceCoordinatorInterceptor resourceCoordinatorInterceptor;
  14. @Pointcut("@annotation(org.mengyun.tcctransaction.api.Compensable)")
  15. public void transactionContextCall() {
  16.  
  17. }
  18.  
  19. @Around("transactionContextCall()")
  20. public Object interceptTransactionContextMethod(ProceedingJoinPoint pjp) throws Throwable {
  21. return resourceCoordinatorInterceptor.interceptTransactionContextMethod(pjp);
  22. }
  23.  
  24. public void setResourceCoordinatorInterceptor(ResourceCoordinatorInterceptor resourceCoordinatorInterceptor) {
  25. this.resourceCoordinatorInterceptor = resourceCoordinatorInterceptor;
  26. }
  27.  
  28. public abstract int getOrder();
  29. }
  1. package org.mengyun.tcctransaction.spring;
  2.  
  3. import org.aspectj.lang.annotation.Aspect;
  4. import org.mengyun.tcctransaction.interceptor.ResourceCoordinatorAspect;
  5. import org.mengyun.tcctransaction.interceptor.ResourceCoordinatorInterceptor;
  6. import org.mengyun.tcctransaction.support.TransactionConfigurator;
  7. import org.springframework.core.Ordered;
  8.  
  9. /**
  10. * Created by changmingxie on 11/8/15.
  11. */
  12. @Aspect
  13. public class ConfigurableCoordinatorAspect extends ResourceCoordinatorAspect implements Ordered {
  14. private TransactionConfigurator transactionConfigurator;
  15. public void init() {
  16. ResourceCoordinatorInterceptor resourceCoordinatorInterceptor = new ResourceCoordinatorInterceptor();
  17. resourceCoordinatorInterceptor.setTransactionManager(transactionConfigurator.getTransactionManager());
  18. this.setResourceCoordinatorInterceptor(resourceCoordinatorInterceptor);
  19. }
  20.  
  21. @Override
  22. public int getOrder() {
  23. return Ordered.HIGHEST_PRECEDENCE + 1;
  24. }
  25.  
  26. public void setTransactionConfigurator(TransactionConfigurator transactionConfigurator) {
  27. this.transactionConfigurator = transactionConfigurator;
  28. }
  29. }
  1. package org.mengyun.tcctransaction.interceptor;
  2.  
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.reflect.MethodSignature;
  5. import org.mengyun.tcctransaction.InvocationContext;
  6. import org.mengyun.tcctransaction.Participant;
  7. import org.mengyun.tcctransaction.Transaction;
  8. import org.mengyun.tcctransaction.TransactionManager;
  9. import org.mengyun.tcctransaction.api.Compensable;
  10. import org.mengyun.tcctransaction.api.TransactionContext;
  11. import org.mengyun.tcctransaction.api.TransactionStatus;
  12. import org.mengyun.tcctransaction.api.TransactionXid;
  13. import org.mengyun.tcctransaction.support.FactoryBuilder;
  14. import org.mengyun.tcctransaction.utils.CompensableMethodUtils;
  15. import org.mengyun.tcctransaction.utils.ReflectionUtils;
  16.  
  17. import java.lang.reflect.Method;
  18.  
  19. /**
  20. * Created by changmingxie on 11/8/15.
  21. */
  22. public class ResourceCoordinatorInterceptor {
  23. private TransactionManager transactionManager;
  24. public void setTransactionManager(TransactionManager transactionManager) {
  25. this.transactionManager = transactionManager;
  26. }
  27.  
  28. public Object interceptTransactionContextMethod(ProceedingJoinPoint pjp) throws Throwable {
  29. Transaction transaction = transactionManager.getCurrentTransaction();
  30. if (transaction != null) {
  31. switch (transaction.getStatus()) {
  32. case TRYING:
  33. enlistParticipant(pjp);
  34. break;
  35. case CONFIRMING:
  36. break;
  37. case CANCELLING:
  38. break;
  39. }
  40. }
  41. return pjp.proceed(pjp.getArgs());
  42. }
  43.  
  44. private void enlistParticipant(ProceedingJoinPoint pjp) throws IllegalAccessException, InstantiationException {
  45. Method method = CompensableMethodUtils.getCompensableMethod(pjp);
  46. if (method == null) {
  47. throw new RuntimeException(String.format("join point not found method, point is : %s", pjp.getSignature().getName()));
  48. }
  49. Compensable compensable = method.getAnnotation(Compensable.class);
  50.  
  51. String confirmMethodName = compensable.confirmMethod();
  52. String cancelMethodName = compensable.cancelMethod();
  53.  
  54. Transaction transaction = transactionManager.getCurrentTransaction();
  55. TransactionXid xid = new TransactionXid(transaction.getXid().getGlobalTransactionId());
  56.  
  57. if (FactoryBuilder.factoryOf(compensable.transactionContextEditor()).getInstance().get(pjp.getTarget(), method, pjp.getArgs()) == null) {
  58. FactoryBuilder.factoryOf(compensable.transactionContextEditor()).getInstance().set(new TransactionContext(xid, TransactionStatus.TRYING.getId()), pjp.getTarget(), ((MethodSignature) pjp.getSignature()).getMethod(), pjp.getArgs());
  59. }
  60.  
  61. Class targetClass = ReflectionUtils.getDeclaringType(pjp.getTarget().getClass(), method.getName(), method.getParameterTypes());
  62.  
  63. InvocationContext confirmInvocation = new InvocationContext(targetClass,
  64. confirmMethodName,
  65. method.getParameterTypes(), pjp.getArgs());
  66.  
  67. InvocationContext cancelInvocation = new InvocationContext(targetClass,
  68. cancelMethodName,
  69. method.getParameterTypes(), pjp.getArgs());
  70.  
  71. Participant participant =
  72. new Participant(
  73. xid,
  74. confirmInvocation,
  75. cancelInvocation,
  76. compensable.transactionContextEditor());
  77. transactionManager.enlistParticipant(participant);
  78. }
  79. }

一个事物对象有多个参与者

事物包含了多个参与者,操作包含在了参与者内部

  1. package org.mengyun.tcctransaction;
  2.  
  3. import org.mengyun.tcctransaction.api.TransactionContext;
  4. import org.mengyun.tcctransaction.api.TransactionStatus;
  5. import org.mengyun.tcctransaction.api.TransactionXid;
  6. import org.mengyun.tcctransaction.common.TransactionType;
  7.  
  8. import javax.transaction.xa.Xid;
  9. import java.io.Serializable;
  10. import java.util.ArrayList;
  11. import java.util.Date;
  12. import java.util.List;
  13. import java.util.Map;
  14. import java.util.concurrent.ConcurrentHashMap;
  15.  
  16. /**
  17. * Created by changmingxie on 10/26/15.
  18. */
  19. public class Transaction implements Serializable {
  20.  
  21. private static final long serialVersionUID = 7291423944314337931L;
  22.  
  23. private TransactionXid xid;
  24.  
  25. private TransactionStatus status;
  26.  
  27. private TransactionType transactionType;
  28.  
  29. private volatile int retriedCount = 0;
  30.  
  31. private Date createTime = new Date();
  32.  
  33. private Date lastUpdateTime = new Date();
  34.  
  35. private long version = 1;
  36.  
  37. private List<Participant> participants = new ArrayList<Participant>();
  38.  
  39. private Map<String, Object> attachments = new ConcurrentHashMap<String, Object>();
  40.  
  41. public Transaction() {
  42.  
  43. }
  44.  
  45. public Transaction(TransactionContext transactionContext) {
  46. this.xid = transactionContext.getXid();
  47. this.status = TransactionStatus.TRYING;
  48. this.transactionType = TransactionType.BRANCH;
  49. }
  50.  
  51. public Transaction(TransactionType transactionType) {
  52. this.xid = new TransactionXid();
  53. this.status = TransactionStatus.TRYING;
  54. this.transactionType = transactionType;
  55. }
  56.  
  57. public void enlistParticipant(Participant participant) {
  58. participants.add(participant);
  59. }
  60. public Xid getXid() {
  61. return xid.clone();
  62. }public void commit() {
  63. for (Participant participant : participants) {
  64. participant.commit();
  65. }
  66. }
  67. public void rollback() {
  68. for (Participant participant : participants) {
  69. participant.rollback();
  70. }
  71. }
  72. .....
  73. }

每个参与者对象,包含了confirm/cancel的执行上下文以及terminator执行器

  1. package org.mengyun.tcctransaction;
  2.  
  3. import org.mengyun.tcctransaction.api.TransactionContext;
  4. import org.mengyun.tcctransaction.api.TransactionContextEditor;
  5. import org.mengyun.tcctransaction.api.TransactionStatus;
  6. import org.mengyun.tcctransaction.api.TransactionXid;
  7.  
  8. import java.io.Serializable;
  9.  
  10. /**
  11. * Created by changmingxie on 10/27/15.
  12. */
  13. public class Participant implements Serializable {
  14.  
  15. private static final long serialVersionUID = 4127729421281425247L;
  16.  
  17. private TransactionXid xid;
  18.  
  19. private InvocationContext confirmInvocationContext;
  20.  
  21. private InvocationContext cancelInvocationContext;
  22.  
  23. private Terminator terminator = new Terminator();
  24.  
  25. Class<? extends TransactionContextEditor> transactionContextEditorClass;
  26.  
  27. public Participant() {
  28.  
  29. }
  30.  
  31. public Participant(TransactionXid xid, InvocationContext confirmInvocationContext, InvocationContext cancelInvocationContext, Class<? extends TransactionContextEditor> transactionContextEditorClass) {
  32. this.xid = xid;
  33. this.confirmInvocationContext = confirmInvocationContext;
  34. this.cancelInvocationContext = cancelInvocationContext;
  35. this.transactionContextEditorClass = transactionContextEditorClass;
  36. }
  37.  
  38. public Participant(InvocationContext confirmInvocationContext, InvocationContext cancelInvocationContext, Class<? extends TransactionContextEditor> transactionContextEditorClass) {
  39. this.confirmInvocationContext = confirmInvocationContext;
  40. this.cancelInvocationContext = cancelInvocationContext;
  41. this.transactionContextEditorClass = transactionContextEditorClass;
  42. }
  43.  
  44. public void setXid(TransactionXid xid) {
  45. this.xid = xid;
  46. }
  47.  
  48. public void rollback() {
  49. terminator.invoke(new TransactionContext(xid, TransactionStatus.CANCELLING.getId()), cancelInvocationContext, transactionContextEditorClass);
  50. }
  51. public void commit() {
  52. terminator.invoke(new TransactionContext(xid, TransactionStatus.CONFIRMING.getId()), confirmInvocationContext, transactionContextEditorClass);
  53. }
  54. }

上下文中包含了执行所需的类,方法,参数类型,参数

  1. package org.mengyun.tcctransaction;
  2.  
  3. import java.io.Serializable;
  4.  
  5. /**
  6. * Created by changmingxie on 11/9/15.
  7. */
  8. public class InvocationContext implements Serializable {
  9.  
  10. private static final long serialVersionUID = -7969140711432461165L;
  11. private Class targetClass;
  12.  
  13. private String methodName;
  14.  
  15. private Class[] parameterTypes;
  16.  
  17. private Object[] args;
  18.  
  19. }

执行器,反射调用执行

  1. package org.mengyun.tcctransaction;
  2.  
  3. import org.mengyun.tcctransaction.api.TransactionContext;
  4. import org.mengyun.tcctransaction.api.TransactionContextEditor;
  5. import org.mengyun.tcctransaction.support.FactoryBuilder;
  6. import org.mengyun.tcctransaction.utils.StringUtils;
  7.  
  8. import java.io.Serializable;
  9. import java.lang.reflect.Method;
  10.  
  11. /**
  12. * Created by changmingxie on 10/30/15.
  13. */
  14. public class Terminator implements Serializable {
  15. private static final long serialVersionUID = -164958655471605778L;
  16. public Terminator() {
  17. }
  18. public Object invoke(TransactionContext transactionContext, InvocationContext invocationContext, Class<? extends TransactionContextEditor> transactionContextEditorClass) {
  19. if (StringUtils.isNotEmpty(invocationContext.getMethodName())) {
  20. try {
  21. Object target = FactoryBuilder.factoryOf(invocationContext.getTargetClass()).getInstance();
  22. Method method = null;
  23. method = target.getClass().getMethod(invocationContext.getMethodName(), invocationContext.getParameterTypes());
  24. FactoryBuilder.factoryOf(transactionContextEditorClass).getInstance().set(transactionContext, target, method, invocationContext.getArgs());
  25. return method.invoke(target, invocationContext.getArgs());
  26. } catch (Exception e) {
  27. throw new SystemException(e);
  28. }
  29. }
  30. return null;
  31. }
  32. }

在看事物管理器之前先看下周边的几个实现,

首先生成一个事物,先要生成一个唯一ID,本例中是这么生成的,TransactionID生成 UUID.randomUUID() 再处理

  1. private static byte[] uuidToByteArray(UUID uuid) {
  2. ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
  3. bb.putLong(uuid.getMostSignificantBits());
  4. bb.putLong(uuid.getLeastSignificantBits());
  5. return bb.array();
  6. }

其次再看对事物对象的存储,基本就是基于模板方法的实现,接口中包含crud,缓存模板中定义了基本方法对cache的使用,cache也用的基本款,具体针对不同的存储介质有具体的存取实现,比如zk的目录/TCC,redis的TCC:,文本系统是/tcc,jdbc的表等

CacheBuilder.newBuilder().expireAfterAccess(expireDuration, TimeUnit.SECONDS).maximumSize(1000).build();

TransactionManager是对整个事物的发起,注册以及管理等

  1. package org.mengyun.tcctransaction;
  2.  
  3. import org.apache.log4j.Logger;
  4. import org.mengyun.tcctransaction.api.TransactionContext;
  5. import org.mengyun.tcctransaction.api.TransactionStatus;
  6. import org.mengyun.tcctransaction.common.TransactionType;
  7.  
  8. import java.util.Deque;
  9. import java.util.LinkedList;
  10. import java.util.concurrent.ExecutorService;
  11.  
  12. /**
  13. * Created by changmingxie on 10/26/15.
  14. */
  15. public class TransactionManager {
  16.  
  17. static final Logger logger = Logger.getLogger(TransactionManager.class.getSimpleName());
  18.  
  19. private TransactionRepository transactionRepository;
  20.  
  21. private static final ThreadLocal<Deque<Transaction>> CURRENT = new ThreadLocal<Deque<Transaction>>();
  22. private ExecutorService executorService;
  23.  
  24. public void setTransactionRepository(TransactionRepository transactionRepository) {
  25. this.transactionRepository = transactionRepository;
  26. }
  27.  
  28. public void setExecutorService(ExecutorService executorService) {
  29. this.executorService = executorService;
  30. }
  31.  
  32. public TransactionManager() {
  33. }
  34.  
  35. public Transaction begin() {
  36. Transaction transaction = new Transaction(TransactionType.ROOT);
  37. transactionRepository.create(transaction);
  38. registerTransaction(transaction);
  39. return transaction;
  40. }
  41.  
  42. public Transaction propagationNewBegin(TransactionContext transactionContext) {
  43. Transaction transaction = new Transaction(transactionContext);
  44. transactionRepository.create(transaction);
  45. registerTransaction(transaction);
  46. return transaction;
  47. }
  48.  
  49. public Transaction propagationExistBegin(TransactionContext transactionContext) throws NoExistedTransactionException {
  50. Transaction transaction = transactionRepository.findByXid(transactionContext.getXid());
  51. if (transaction != null) {
  52. transaction.changeStatus(TransactionStatus.valueOf(transactionContext.getStatus()));
  53. registerTransaction(transaction);
  54. return transaction;
  55. } else {
  56. throw new NoExistedTransactionException();
  57. }
  58. }
  59.  
  60. public void commit(boolean asyncCommit) {
  61. final Transaction transaction = getCurrentTransaction();
  62. transaction.changeStatus(TransactionStatus.CONFIRMING);
  63. transactionRepository.update(transaction);
  64. if (asyncCommit) {
  65. try {
  66. Long statTime = System.currentTimeMillis();
  67. executorService.submit(new Runnable() {
  68. @Override
  69. public void run() {
  70. commitTransaction(transaction);
  71. }
  72. });
  73. logger.debug("async submit cost time:" + (System.currentTimeMillis() - statTime));
  74. } catch (Throwable commitException) {
  75. logger.warn("compensable transaction async submit confirm failed, recovery job will try to confirm later.", commitException);
  76. throw new ConfirmingException(commitException);
  77. }
  78. } else {
  79. commitTransaction(transaction);
  80. }
  81. }
  82.  
  83. public void rollback(boolean asyncRollback) {
  84. final Transaction transaction = getCurrentTransaction();
  85. transaction.changeStatus(TransactionStatus.CANCELLING);
  86. transactionRepository.update(transaction);
  87. if (asyncRollback) {
  88. try {
  89. executorService.submit(new Runnable() {
  90. @Override
  91. public void run() {
  92. rollbackTransaction(transaction);
  93. }
  94. });
  95. } catch (Throwable rollbackException) {
  96. logger.warn("compensable transaction async rollback failed, recovery job will try to rollback later.", rollbackException);
  97. throw new CancellingException(rollbackException);
  98. }
  99. } else {
  100. rollbackTransaction(transaction);
  101. }
  102. }
  103.  
  104. private void commitTransaction(Transaction transaction) {
  105. try {
  106. transaction.commit();
  107. transactionRepository.delete(transaction);
  108. } catch (Throwable commitException) {
  109. logger.warn("compensable transaction confirm failed, recovery job will try to confirm later.", commitException);
  110. throw new ConfirmingException(commitException);
  111. }
  112. }
  113.  
  114. private void rollbackTransaction(Transaction transaction) {
  115. try {
  116. transaction.rollback();
  117. transactionRepository.delete(transaction);
  118. } catch (Throwable rollbackException) {
  119. logger.warn("compensable transaction rollback failed, recovery job will try to rollback later.", rollbackException);
  120. throw new CancellingException(rollbackException);
  121. }
  122. }
  123.  
  124. public Transaction getCurrentTransaction() {
  125. if (isTransactionActive()) {
  126. return CURRENT.get().peek();
  127. }
  128. return null;
  129. }
  130.  
  131. public boolean isTransactionActive() {
  132. Deque<Transaction> transactions = CURRENT.get();
  133. return transactions != null && !transactions.isEmpty();
  134. }
  135.  
  136. private void registerTransaction(Transaction transaction) {
  137. if (CURRENT.get() == null) {
  138. CURRENT.set(new LinkedList<Transaction>());
  139. }
  140. CURRENT.get().push(transaction);
  141. }
  142.  
  143. public void cleanAfterCompletion(Transaction transaction) {
  144. if (isTransactionActive() && transaction != null) {
  145. Transaction currentTransaction = getCurrentTransaction();
  146. if (currentTransaction == transaction) {
  147. CURRENT.get().pop();
  148. } else {
  149. throw new SystemException("Illegal transaction when clean after completion");
  150. }
  151. }
  152. }
  153.  
  154. public void enlistParticipant(Participant participant) {
  155. Transaction transaction = this.getCurrentTransaction();
  156. transaction.enlistParticipant(participant);
  157. transactionRepository.update(transaction);
  158. }
  159. }

TCC细读 - 2 核心实现的更多相关文章

  1. TCC细读 - 1 例子流程

    http://www.iocoder.cn/categories/TCC-Transaction/ https://github.com/changmingxie/tcc-transaction 细读 ...

  2. TCC细读 - 3 恢复流程

    重试定时任务,通过外部调度实现 package org.mengyun.tcctransaction.spring.recover; import org.mengyun.tcctransaction ...

  3. 面试被问分布式事务(2PC、3PC、TCC),这样解释没毛病!

    整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 更多优选 一口气说出 9种 分布式ID生成方式,面试官有点懵了 ...

  4. 分布式架构原理解析,Java开发必修课

    1. 分布式术语 1.1. 异常 服务器宕机 内存错误.服务器停电等都会导致服务器宕机,此时节点无法正常工作,称为不可用. 服务器宕机会导致节点失去所有内存信息,因此需要将内存信息保存到持久化介质上. ...

  5. 分布式事务框架Seata及EasyTransaction架构的比对思考

    本文将会对比Seata与EasyTransaction两个分布式事务的一些高层设计,相信大家会有收获. Seata的概述 Seata(曾用名Fescar,开源版本GTS)是阿里的开源分布式事务框架,其 ...

  6. 关于tcc、tlink的编译链接机制的研究

    1.学习过程 在c:\下建立文件夹c,并将编译器tcc.exe.连接器tlink.exe.相关文件c0s.obj.cs.lib.emu.lib.maths.lib放入文件夹中. 要搭建一个简单的C语言 ...

  7. 【原创】分布式事务之TCC事务模型

    引言 在上篇文章<老生常谈--利用消息队列处理分布式事务>一文中留了一个坑,今天来填坑.如下图所示 如果服务A和服务B之间是同步调用,比如服务C需要按流程调服务A和服务B,服务A和服务B要 ...

  8. 终于有人把“TCC分布式事务”实现原理讲明白了!

    之前网上看到很多写分布式事务的文章,不过大多都是将分布式事务各种技术方案简单介绍一下.很多朋友看了还是不知道分布式事务到底怎么回事,在项目里到底如何使用. 所以这篇文章,就用大白话+手工绘图,并结合一 ...

  9. TCC

    严格遵守ACID的分布式事务我们称为刚性事务,而遵循BASE理论(基本可用:在故障出现时保证核心功能可用,软状态:允许中间状态出现,最终一致性:不要求分布式事务打成中时间点数据都是一致性的,但是保证达 ...

随机推荐

  1. 马凯军201771010116《面向对象程序设计(java)》第一周学习总结

    马凯军201771010116<面向对象程序设计(java)>第一周学习总结 第一部分:课程准备部分 填写课程学习 平台注册账号, 平台名称 注册账号 博客园:www.cnblogs.co ...

  2. word转换成HTML 以及IE不兼容问题

    public static bool WordToHtml(string wordFileName, string htmlFileName) { try { Object oMissing = Sy ...

  3. [转] ROS2源码编译和安装

    机器人开源操作系统软件ROS在10年后, 终于推出全新架构的ROS2,代号“ardent”.中文意思为“热心的美洲鳖”,看来ROS2要从ROS1的“海龟”变成“土鳖”系列了. 与此同时,ROS2的编译 ...

  4. 解决Myeclipse通过svn导入项目后,项目直接报错问题

    在使用Myeclipse2015通过SNV导入项目后,项目直接报错,如下图: 点开后报错详细信息如下: Multiple markers at this line - The type java.la ...

  5. Parsing with Compositional Vector Grammars--paper

    这篇和2012年的区别: 1)Max-Margin Training Objective J中RNN变为了CVG 2012-两个词向量合并并打分,这个-两个(词向量,POS)合并并打分 2012年: ...

  6. 【SpringBoot】息队列介绍和SpringBoot2.x整合RockketMQ、ActiveMQ

    ========================13.消息队列介绍和SpringBoot2.x整合RockketMQ.ActiveMQ ======================= 1.JMS介绍和 ...

  7. String引用数据类型

    一.String类的第一种方式 (原文地址:https://blog.csdn.net/wangdajiao/article/details/52087302)1.直接赋值 例:String str ...

  8. Nginx自动安装脚本

    添加一个install_nginx.sh脚本 版本一:(以下脚本为在线自动化安装) #!/bin/bash mkdir /soft cd /soft wget -c http://nginx.org/ ...

  9. C#软件开发实例.私人订制自己的屏幕截图工具(九)使用自己定义光标,QQ截图时的光标

    版权声明:本文为 testcs_dn(微wx笑) 原创文章,非商用自由转载-保持署名-注明出处,谢谢. https://blog.csdn.net/testcs_dn/article/details/ ...

  10. 支付宝 生活号 获取 userId 和 生活号支付

    第一:申请生活号. 第二:激活开发者 模式 ,并且上创 自己的 公钥  ( 支付宝 demo 里面有 ) 第三: 配置 回调地址 ( 用于前端 调用获取 auth_code 的时候 填写的回调地址,支 ...