- 直接上代码,解决方法
- 在需要分布式事务seata的服务模块添加配置
package com.ha.elevator.config; import io.seata.core.context.RootContext; import io.seata.core.exception.TransactionException; import io.seata.tm.api.GlobalTransaction; import io.seata.tm.api.GlobalTransactionContext; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.lang.reflect.Method; @Aspect @Component public class SeataAspect { private final static Logger logger = LoggerFactory.getLogger(SeataAspect.class); @Before("execution(* com.ha.elevator.base.controller.*.*(..))") public void before(JoinPoint joinPoint) throws TransactionException { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); logger.info("拦截到需要分布式事务的方法," + method.getName()); // 此处可用redis或者定时任务来获取一个key判断是否需要关闭分布式事务 GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate(); tx.begin(300000, "test-client"); logger.info("创建分布式事务完毕" + tx.getXid()); } @AfterThrowing(throwing = "e", pointcut = "execution(* com.ha.elevator.base.controller.*.*(..))") public void doRecoveryActions(Throwable e) throws TransactionException { logger.info("方法执行异常:{}", e.getMessage()); if (!StringUtils.isBlank(RootContext.getXID())) { GlobalTransactionContext.reload(RootContext.getXID()).rollback(); } } }
- 完成之后重启服务就可以了,是通过扫描方式手动创建了事务和事务异常回滚
- 这样扫描有一个问题,就是扫描到的所有方法都会被添加上事务,这样就不友好了,所以我自定义了注解,只对使用了注解的方法开启分布式事务
- 先定义一个空注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface EnableSeataScan { /** * 该注解是提供seata事务扫描使用,只对添加了扫描注解的方法开启事务的创建和异常回滚, * 由于feign服务之间的调用,异常无法向调用服务炮异常, * 官方提供的解决方案是aop切入,手动创建事务和手动异常事务回滚 */ }
- 修改aop切入点的扫描方式
import io.seata.core.context.RootContext; import io.seata.core.exception.TransactionException; import io.seata.tm.api.GlobalTransaction; import io.seata.tm.api.GlobalTransactionContext; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.lang.reflect.Method; @Aspect @Component public class SeataAspect { private final static Logger logger = LoggerFactory.getLogger(SeataAspect.class); @Pointcut("@annotation(com.ha.common.core.utils.seata.EnableSeataScan)") private void pointCut() { } @Before("pointCut()") public void before(JoinPoint joinPoint) throws TransactionException { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); logger.info("拦截到需要分布式事务的方法," + method.getName()); // 此处可用redis或者定时任务来获取一个key判断是否需要关闭分布式事务 GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate(); tx.begin(300000, "test-client"); logger.info("创建分布式事务完毕" + tx.getXid()); } @AfterThrowing(throwing = "e", pointcut = "pointCut()") public void doRecoveryActions(Throwable e) throws TransactionException { logger.info("方法执行异常:{}", e.getMessage()); if (!StringUtils.isBlank(RootContext.getXID())) { GlobalTransactionContext.reload(RootContext.getXID()).rollback(); } } }
- 在方法上使用事务注解
- remoteUserService是另一个服务提供出来的api,这个业务流程走向都需要使用上注解,如下
- 在对应的服务方法上使用注解
- 都是经过测试操作滴。。。