数据库悲观锁 乐观锁

首先提到两个概念:脏读 不可重复读 

脏读:上一个访问数据库的请求还没结束 下一个请求来了 就看到上一个请求进行的修改  这就属于脏读 

    比如: a 在提款机 看自己的账户余额 100元  然后存20元 但是还没 落库 这时候b给他打50元 b应该是 100+50  但如果隔离级别不够(读未提交)就会造成b看到的是 120+50 这时 a就产生了脏读 

不可重复读:在一个访问数据库的请求进行时 其他请求进行了数据库修改  这个请求多次看数据库的数据是在变化的 这就属于不可重复读

   比如 :a 在提款机 看自己的账户余额 100元 然后存20元 但是还没 落库 这时候b给他打50元  a应该看到的还是100 但是如果隔离级别不够(不可重复读)就会造成a 看到余额 由100元变成150元 

更多 事务 知识请参考:

接下来看如何处理并发和同步:

同步就是加锁:悲观锁(传统的物理锁)和乐观锁

悲观锁:比较消极 每次有啥操作都上锁 一个人有动作其他人都别动  需要依靠数据库的锁机制 。

举个例子: 

  select * from user where name=”xcg” for update  

  这句sql锁定了user表的符合name = 'xcg' 的记录 ,本次事务提交前 外界无法修改这些记录。 

  Hibernate  的悲观锁 :query.setLockMode("user" , LockMode.UPDATE); 

  生成的语句后面会加上for update 子句来实现悲观锁

      Hibernate 的加锁模式有: 
      Ø LockMode.NONE : 无锁机制。 
      Ø LockMode.WRITE : Hibernate 在 Insert 和 Update 记录的时候会自动获取
      Ø LockMode.READ : Hibernate 在读取记录的时候会自动获取。 
      以上这三种锁机制一般由 Hibernate 内部使用,如 Hibernate 为了保证 Update
      过程中对象不会被外界修改,会在 save 方法实现中自动为目标对象加上 WRITE 锁。

乐观锁:积极向上了很多 悲观锁 会造成很多悲观的现象:在长事务中性能开销大 大家都等着。 乐观锁 更适用于读比较多的情况,这样可以提高吞吐量

     但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。

  乐观锁的实现方式: 版本号控制 CAS算法

    1.版本号:

    在表加一个version字段用来表示数据被修改的次数,在读取数据的时候会读取version , 在提交更新时若version值是现在数据库的version值,就同意提交

    2.CAS算法:

    compare and swap (比较与交换)  是著名的不使用锁的情况下实现多线程之间的变量交换同步,也就是在没有线程阻塞的情况下 实现变量的同步。

    CAS算法有三操作数:需要读写的内存之V  进行比较的值A  拟写入的新值B 

    当且仅当V=A时 CAS通过原子方式用B更新V

  乐观锁只适用于读很多 很少写的情况

posted @ 2019-10-09 16:55  皮肤黝黑的小白  阅读(142)  评论(0编辑  收藏  举报