事务+切面踩坑~~

一,背景描述

对于方法A,做一个切面,前后记录日志,如果这个方法A事务包裹,此时会发生什么,且看代码

二,上代码

1,定义一个切面

less 复制代码
@Component
@Aspect
@Slf4j
public class logAspect {

    @Resource
    LogService logService;

    @Pointcut("execution(public * com.service.ShopResultService.syn*(..))")
    public void logPointCut() {
    }

    @Around("logPointCut()")
    public void process(ProceedingJoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        LogRecord record = logService.start(name);
        try {
            joinPoint.proceed();
            logService.success(record);
        } catch (Throwable throwable) {
            logService.fail(record);
        }
    }
}

定义一个日志切面,里面有logPointCut切点,对于切点,在方法前后打日志,LogRecord对应mysql表

2,日志服务

csharp 复制代码
@Service
public class LogService {

    @Autowired
    LogRecordMapper logRecordhMapper;

    /**
     * 新增
     */
    public LogRecord start(String taskDef) {
        //新增日志
        LogRecord record = new LogRecord();
        record.setProjectNo(taskDef);
        record.setStatus("doing");
        logRecordhMapper.insert(record);
        return record;
    }

    /**
     * 成功
     */
    public void success(LogRecord record) {
        //更新日志
        auth.setStatus("success");
        logRecordhMapper.updateById(record);
    }

    /**
     * 失败
     */
    public void fail(LogRecord record) {
        //失败日志
        auth.setStatus("fail");
        logRecordhMapper.updateById(record);
    }
}

如果任务执行成功,日志更新为success,否则是fail。

3,被切的服务

csharp 复制代码
@Transactional
public void synData() {
    UserData userData = new UserData();
    userData.setShopName("test");
    UserDataMapper.insert(userData);
    System.out.println("over");
}

4,问题

arduino 复制代码
 public LogRecord start(String taskDef)

发现日志方法虽然没有加事务,但其实是在事务里的,也就是说日志方法记录完成后,表暂态是没有记录的,此时日志是被切面事务包裹在一起,也就是说,如果synData失败,切面也会抛异常,因为update一条数据库不存在的记录。

三,结论

spring事务和切面都是通过代理完成,代理链的设计导致这两个逻辑绑定在一起

解决方案:1,使用注解,切面在事务之前执行

java 复制代码
@Order(Ordered.LOWEST_PRECEDENCE - 1)
less 复制代码
@Component
@Aspect
@Slf4j
@Order(Ordered.LOWEST_PRECEDENCE - 1)
public class logAspect {

    @Resource
    LogService logService;

    @Pointcut("execution(public * com.service.ShopResultService.syn*(..))")
    public void logPointCut() {
    }

    @Around("logPointCut()")
    public void process(ProceedingJoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        LogRecord record = logService.start(name);
        try {
            joinPoint.proceed();
            logService.success(record);
        } catch (Throwable throwable) {
            logService.fail(record);
        }
    }
}

解决方案2,使用spring事务隔离级别,将两个事务隔离开

csharp 复制代码
@Service
public class LogService {

    @Autowired
    LogRecordMapper logRecordhMapper;

    /**
     * 新增
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public LogRecord start(String taskDef) {
        //新增日志
        LogRecord record = new LogRecord();
        record.setProjectNo(taskDef);
        record.setStatus("doing");
        logRecordhMapper.insert(record);
        return record;
    }

    /**
     * 成功
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void success(LogRecord record) {
        //更新日志
        auth.setStatus("success");
        logRecordhMapper.updateById(record);
    }

    /**
     * 失败
     */     
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void fail(LogRecord record) {
        //失败日志
        auth.setStatus("fail");
        logRecordhMapper.updateById(record);
    }
}
相关推荐
IT_陈寒17 分钟前
Vite打包时静态资源404?加个斜杠就能解决
前端·人工智能·后端
程序员爱钓鱼25 分钟前
Go 输入输出详解
后端·面试·go
程序员爱钓鱼33 分钟前
Rust 生命周期详解:生命周期标注、约束与真实项目应用
后端·面试·rust
MoonBit月兔35 分钟前
MoonBit 受邀亮相 SPLASH/ISSTA 2026,与 Java、Rust、Eiffel、D 语言核心贡献者同场交流
开发语言·后端·rust
维克兜率天11 小时前
【维克】ARMA模型:AR与MA的完美结合
后端·restful
是未才12 小时前
从输入 URL 到页面返回:DNS、路由、TLS 与 HTTP 完整链路
java·后端·计算机网络
上海安当技术12 小时前
半天接入:USBKey RESTful API + C 动态库,Web 和 C/S 两套集成路径实战
前端·后端·restful·集成·usbkey
DevUI团队12 小时前
从“即兴创作”到“规格先行”,华为云码道(CodeArts)代码智能体持续深耕企业级规范驱动开发能力
前端·人工智能·后端
weixin_4316004413 小时前
NestJS 入门(3):Guard 如何挡住未登录请求?
前端·后端·学习·nest.js
IT_陈寒14 小时前
JavaScript类型转换把我坑惨了,这破玩意真该早点搞明白
前端·人工智能·后端