seata使用回顾
- 在feign接口调用方使用@GlobalTransactional
- 在被调用方使用@Transactional
- 当调用方出现异常,整体会进行事务的回滚
- 当被调用方出现了异常会出现两种情况
- 如果系统进行了全局异常捕获,被调用方会进行事务回滚,调用方不会
- 如果系统没有进行全局异常捕获或者没有捕获调用方出现的异常,双方都会出现事务的回滚
使用AOP方式解决事务失效问题
一般情况下,我们的系统为了能给前端更好的响应,而不是把一串很长的错误信息给到前端,都会进行全局异常的捕获,所以就会出现seata分布式事务失效的问题
针对此种问题,我们可以使用AOP切面的方式进行解决
编写AOP切面类
package com.ajie.api.aspect;
import com.ajie.common.utils.StringUtils;
import io.seata.core.context.RootContext;
import io.seata.core.exception.TransactionException;
import io.seata.spring.annotation.GlobalTransactional;
import io.seata.tm.api.GlobalTransaction;
import io.seata.tm.api.GlobalTransactionContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
/**
* @Description:
* @Author: ajie
*/
@Component
@Aspect
@Slf4j
public class SeataTransactionAspect {
@Before("execution(* com.ajie.*.service.impl..*.*(..))")
public void beginTransaction(JoinPoint joinPoint) throws TransactionException {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
// 获取到方法上的注解
GlobalTransactional globalTransactional = methodSignature.getClass()
.getAnnotation(GlobalTransactional.class);
Transactional transactional = methodSignature.getClass().getAnnotation(Transactional.class);
if (globalTransactional != null || transactional != null) {
// 如果方法上有事务注解,就手动开启分布式事务
log.warn("手动开启全局事务");
GlobalTransaction gt = GlobalTransactionContext.getCurrentOrCreate();
gt.begin();
}
}
@AfterThrowing(
throwing = "throwable",
pointcut = "execution(* com.ajie.*.service.impl..*.*(..))"
)
public void rollback(Throwable throwable) throws TransactionException {
log.warn("捕获到的异常信息,则回滚,异常信息为:{}", throwable.getMessage());
// 从当前线程获得xid
String xid = RootContext.getXID();
if (StringUtils.isNotBlank(xid)) {
GlobalTransactionContext.reload(xid).rollback();
}
}
@AfterReturning(
returning = "result",
pointcut = "execution(* com.ajie.*.service.impl..*.*(..))"
)
public void commit(JoinPoint joinPoint, Object result) throws TransactionException {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
// 获取到方法上的注解
GlobalTransactional globalTransactional = methodSignature.getClass()
.getAnnotation(GlobalTransactional.class);
Transactional transactional = methodSignature.getClass().getAnnotation(Transactional.class);
if (globalTransactional != null || transactional != null) {
// 如果方法上有事务注解,就手动提交全局事务
log.warn("手动提交全局事务");
// 从当前线程获得xid
String xid = RootContext.getXID();
if (StringUtils.isNotBlank(xid)) {
GlobalTransactionContext.reload(xid).commit();
}
}
}
}