美文网首页
SpringAOP会导致的一些问题

SpringAOP会导致的一些问题

作者: 耐得千事烦 | 来源:发表于2019-08-17 23:08 被阅读0次

前言

之前的系列文章已经把AOP说的挺明白了,现在我们来说一些日常的可能在用到spring的时候会遇到的一些奇怪的问题,而这类问题的问题就出现在在AOP这块。


\color{green}{问题1}
在使用Spring事务的时候,如果在方法上加上synchronized锁依然会导致线程是非安全的问题。可能有点说的不明白,我们直接贴代码吧。

  • 测试代码:
@RestController
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    @RequestMapping("/add")
    public void addEmployee() {
        for (int i = 0; i < 1000; i++) {
            new Thread(() -> employeeService.addEmployee()).start();
        }
    }


}

@Service
public class EmployeeService {
    @Autowired
    private EmployeeRepository employeeRepository;
    @Transactional
    public synchronized void addEmployee() {
        // 查出ID为8的记录,然后每次将年龄增加一
        Employee employee = employeeRepository.getOne(8);
        System.out.println(employee);
        Integer age = employee.getAge();
        employee.setAge(age + 1);

        employeeRepository.save(employee);
    }

}

描述一下代码业务吧:开启1000个线程,每个线程的工作是去查询一下员工的数据,然后把员工的年龄数据进行加1的操作,并且进行保存。事先申明在数据库层面并没有用到悲观锁或者乐观锁。当然根据上面的代码(已经在方法上加了锁),按理说最终的结果该员工的年龄应该是1000。

代码贴完,并且也把业务说明清楚了,我们来看一下控制台打印情况:


SQL打印情况.png

看到什么了么?SQL执行的情况并非是我们想象中的串行进行的。这就会导致对同一个值进行重复修改,那么必然的最终的员工的年龄一定是小于1000的。那么问题来了,为什么我已经在方法上加了synchronized关键字了,结果方法依然没有出现串行呢?

  • 描述完毕,现在进行解答:
    首先先说一下,这个问题好像是事务与synchronized锁的问题,但是我们要知道一点,Spring实现事务的机制是通过SpringAOP来完成的(后面会发一篇文章来描述一下Spring事务的实现机制)。我说的这么明白,那么大家也应该明白了,问题的原因肯定是不会出现在synchronized锁上了,对,就是出现在springAOP的实现机制上。
    我们知道在IOC容器初始化bean的时候,在初始化完bean后,会通过BeanPostProcessor接口里的方法来将目标对象替换成代理类对象,而代理类是已经把目标对象里的方法进行了增强处理(可以去看一下之前写的关于AOP的文章)
    而如何增强的呢?我们以JDK动态代理为例子,通过实现InvocationHandler接口的invoke方法来实现增强的,我们来看一下Spring实现事务这块是如何实现相关invoke方法的:


    Spring事务实现invoke方法部分源码.png

在多线程环境下,就可能会出现:方法执行完了(synchronized代码块执行完了),事务还没提交,别的线程可以进入被synchronized修饰的方法,再读取的时候,读到的是还没提交事务的数据,这个数据不是最新的,所以就出现了这个问题

再聊的深一点:其实这个问题的本质是要对这个事务方法进行串行化处理(不知道大家能不能理解,如果可以理解,那就说明是真的懂了)

处理方法有俩种:
1.去掉synchronized关键字,直接在事务注解上加上配置,让数据库的隔离等级提升到serializable串行化。(数据层层面的串行化)

  1. 由上面的分析可以知道,看似synchronized关键字锁定了整个addEmployee方法,但是其实它只是锁了一部分代码的代码块而已,并没有整个锁住这个事务方法,我们可以在外层套个壳子,然后锁住这个壳子就行了:(代码层面的串行化)
    新建一个名叫SynchronizedService类,让其去调用addEmployee()方法,整个代码如下:
@RestController
public class EmployeeController {
    @Autowired
    private SynchronizedService synchronizedService ;
    @RequestMapping("/add")
    public void addEmployee() {
        for (int i = 0; i < 1000; i++) {
            new Thread(() -> synchronizedService.synchronizedAddEmployee()).start();
        }
    }
}

// 新建的Service类
@Service
public class SynchronizedService {
    @Autowired
    private EmployeeService employeeService ; 
    // 同步
    public synchronized void synchronizedAddEmployee() {
        employeeService.addEmployee();
    }
}

@Service
public class EmployeeService {
    @Autowired
    private EmployeeRepository employeeRepository;
    @Transactional
    public void addEmployee() {
        // 查出ID为8的记录,然后每次将年龄增加一
        Employee employee = employeeRepository.getOne(8);
        System.out.println(Thread.currentThread().getName() + employee);
        Integer age = employee.getAge();
        employee.setAge(age + 1);

        employeeRepository.save(employee);
    }
}

\color{green}{问题2}
在AOP中进行增强俩个方法(该俩方法在一个类里),如果其中一个方法里面调用了另一个方法,那么就会导致一个问题。该方法里调用的另一个方法并没有得到我们预想中的增强处理,这又是怎么回事呢?

暂时先写到这,后面会把这块给补上的......

相关文章

  • SpringAOP会导致的一些问题

    前言 之前的系列文章已经把AOP说的挺明白了,现在我们来说一些日常的可能在用到spring的时候会遇到的一些奇怪的...

  • Spring Security-原始篇(XML配置版)

    该篇章会跳过Spring、SpringAOP、MyBatis基础部分的讨论,专注于Spring Security部...

  • spring框架 AOP

    10、 代理模式 为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP 和 Spring...

  • Mycat 整合 MySQL 8.x 踩坑实践

    Mycat 目前还未全面支持MySQL 8以上的版本,可能会导致一些问题,例如Mycat连接MySQL 8时可能会...

  • spring源码解析-基于注解的SpringAOP源码解析(二)

    在Spring源码解析之基于注解的SpringAOP源码解析(一)中,我们搭建了SpringAOP源码分析的环境,...

  • 六、AOP实现自动的系统日志功能

    一、本课目标 掌握SpringAOP的配置 二、使用SpringAOP实现日志输出 在下面的这个示例中,通过Spr...

  • SpringAOP

    SpringAOP-PPT SpringAOP视频 面向切面编程(AOP)通过提供另外一种思考程序结构的途经来弥补...

  • Spring AOP源码分析

    前言 通过之前的俩篇文章,我们大体上已经知道如何使用SpringAOP了,同时也了解到了SpringAOP底层使用...

  • Spring AOP 一

    上一篇讲了jdk动态代理,下面我们来说说SpringAOP。SpringAOP是基于动态代理的,它对动态代理又做了...

  • springAOP

    springAOP切面拦截参数进行校验。

网友评论

      本文标题:SpringAOP会导致的一些问题

      本文链接:https://www.haomeiwen.com/subject/vxwksctx.html