从Spring的AOP角度看Synchronized锁失效和事务失效的情况

这个锁失效是前年了遇到的一个bug,在一个方法上加了Synchronized,为了避免同一时间产生两条相同的单据,但是很明显,它失效了,不然也不会有今天的这篇文章。

出现这个bug的是一个老项目,而且这个bug很早之前就发现了,前人应该也发现了,对数据进行了所谓的特殊处理,所以一直也就那么运行下去。老项目本着能运行就不要乱动的原则,就没怎么处理了。后面需要对这个模块进行重构,就决定把这个问题解决了。

当时这个问题看了很久,也分析了很久,没有头绪,想着这个bean是单例的应该是不存在锁不住的情况。现在想想还是太年轻了。

产生的原因

我们来回顾一下spring进行事务处理的逻辑:如果一个方法需要开启声明式事务,会进行代理,在执行的逻辑之前和之后进行增强。

比如 我们需要更新数据库的数据,数据库现在的数据是0

模拟同时进行200次操作

    @GetMapping("test_tran")
    public R<Void> testTran() {

        ThreadUtil.execute(() -> {
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    for (int i1 = 0; i1 < 20; i1++) {
                        testBiz.testProxy();
                    }
                }).start();
            }
        });

        return R.ok();
    }
    
    // ========== testBiz ========== 
    // testBiz方法 然后操作的方法加了锁
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized int testProxy() {

        System.out.println(this.hashCode());
        // 之前的业务大致流程是 查询数据是否存在
        int num = sysConfigMapper.getNum();
        // 如果数据存在就直接返回 不存在就新增
        // 不太好模拟 这边改成获取数据 在+1好模拟一点
        sysConfigMapper.updateNum(num + 1);
        // 模拟业务耗时
        ThreadUtil.safeSleep(20);

       return num;
    }
    
    // ========== mapper 方法 ========== 
    @Select("select incr from test_sync where id = 1")
    int getNum();

    @Update("update test_sync set incr = #{i} where id = 1")
    void updateNum(int i);
复制代码

如果正常的话,一次执行完数据库的数据应该是200

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值