• 独占锁 和 CAS


    先提出讨论一个问题: 数据库修改 库存 应该怎么写?

    sql大概这么写: update goods set num = newNum where id = #{id }; 如果两个线程都在 写 那么很容易 被冲掉修改。

    很多时候我们会考虑数据的并发,会考虑加锁。

    悲观乐观的角度

    数据库有悲观锁 和乐观锁。

      悲观锁写法:

        select * from goods where id = #{id} for update;

        update goods set num = newNum where id = #{id };

        分析: 在 for update 的时候,已经个这个行 数据加了 一个悲观的 写锁。这时候别的 关于这行的修改操作需要获取这个行的锁,明显获取不到,也就是 只有打事务提交以后 别的关于写这行的事务才有机会获取锁,才能执行。 不会出并发问题。

    我们在看,锁的时间   forupdate 查询 到事务提交完成都占着。 

      

      乐观锁的写法: 乐观锁不是 读锁,也不是写锁,可以说不是锁,是一种 很乐观的标记,乐观的认为这个99% 可以成功,并且如果真的出了并发问题,我也能知道,并且重试。  这种思想叫做  CAS  ,检查并且更新。

        select * from goods where id = #{id} ;

        update goods set num = #{ newNum  },version = version+1 where id = #{id } and version = #{ oldVersion};

        

        分析: 查询的时候其实做了一个 标记 version ,但是没有在这行上面加 独占锁 。 update的时候如果version 没有改变,那么我们认定 这行记录没有被修改过。 否则 说明 这个 操作冲突了,这时候应该 从试。

    然后我们仔细思考 数据库的 写入其实自己会加锁的。写锁也就是独占锁。所以在A 事务写入数据的时候回获取到这吧写锁,知道A事务提交才释放,这时候 B事务拿不到这个锁,对于这行数据的写入会排队。死哦如操作是串行 的了。

      既然这样我们大可以这样写: update goods set num = #{ newNum  } where id = #{id } ; 2 个事务如果同时执行,桶一瞬间只有一个在执行者句话 ,也就不会出并发问题。 

      但是真的不会出问题吗?

        写法1 update goods set num = #{ newNum  } where id = #{id } ; 备注 newNum   = 101

        写法2 update goods set num = num +1 where id = #{id } ;

        一样吗? 那种会出问题?

        明显写法2 不会出问题,前面已经说了 同一个锁的数据写入 是排序的(  这里一般是行级锁 或者间隙锁 )

        写法1 为啥会出问题了? 因为 set num = 101 ,看起来是对的,但是 其实 并发的时候就错了。问题出在哪里?出在我们查询到100 的时候没有加锁(  读写锁规定,读的时候加读锁,读锁一加,写锁就加不上,但是mysql 不是这样的,mysql 的读是非锁定读 ),

        因为没有加读锁,所以事务B可以获取写锁,吧 100 改成 101。 但是我们程序还是用的 100.问题就出了。

        怎么解决?

          1 在 查询的时候就加锁 这样 后面 就不会被别人修改了。   上面 for update 的写法。 效率最低,但是非常有效。而且简单易懂。

          2 我认为不会有人来改,但是如果有人来改我会知道并且重试   乐观锁写法。 100% 的 可以用,需要设置 version字段,然后 并发操作以后,需要重试 。 如果并发太多反复 重试,不如直接 悲观锁。比如90% 重试,不如直接排队读了在写。

          3 我 如果我修改的时候 不是 前面查询的值 而是去的 当前的最新数据。 也不会出问题。(  简单的 加减可以,但是复杂的计算,比通过 当前值去别的系统 的得到一个值 ,这种情况就不行了 )  100% 不冲突,但是不是100% 的情况可以用。

        

        读锁会阻止写锁,所以mysql 为了效率是不会 加 读锁的,在读的时候不能写,那效率的多低 ?

    读懂以后,什么时候怎么用 很明显了吧。

  • 相关阅读:
    java中float和double的区别
    常用的排序算法及其适用场景
    高级排序
    LoadRunner 学习笔记(1)性能测试常见术语
    Oracle 常用函数
    oracle 自定义函数
    Oracle 异常处理
    Oracle 包(package)
    CF1332B Composite Coloring(数学)
    CF55D Beautiful(数位dp)
  • 原文地址:https://www.cnblogs.com/cxygg/p/14243721.html
Copyright © 2020-2023  润新知