SpringAOP会导致的一些问题

前言

之前的系列文章已经把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中进行增强俩个方法(该俩方法在一个类里),如果其中一个方法里面调用了另一个方法,那么就会导致一个问题。该方法里调用的另一个方法并没有得到我们预想中的增强处理,这又是怎么回事呢?

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容