事务+切面踩坑~~

一,背景描述

对于方法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);
    }
}
相关推荐
毕设源码-钟学长15 小时前
【开题答辩全过程】以 基于SpringBoot的智能书城推荐系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
青春男大16 小时前
Redis和RedisTemplate快速上手
java·数据库·redis·后端·spring·缓存
张张努力变强17 小时前
C++ 类和对象(四):const成员函数、取地址运算符重载全精讲
开发语言·数据结构·c++·后端
不吃香菜学java18 小时前
springboot左脚踩右脚螺旋升天系列-整合开发
java·spring boot·后端·spring·ssm
奋进的芋圆20 小时前
Java 锁事详解
java·spring boot·后端
郑州光合科技余经理20 小时前
技术架构:海外版外卖平台搭建全攻略
java·大数据·人工智能·后端·小程序·架构·php
科威舟的代码笔记20 小时前
SpringBoot配置文件加载顺序:一场配置界的权力游戏
java·spring boot·后端·spring
血小板要健康21 小时前
Spring IoC & DI (下)
java·前端·spring boot·后端·spring·servlet·java-ee
PP东21 小时前
Flowable学习(一)——spring boot 部署
后端·学习·flowable
问今域中21 小时前
Acwing的SpringBoot项目总结
java·spring boot·后端