悲观锁 & 乐观锁

悲观锁:总是假设最坏的情况,每次去拿数据的时候认为somebody会修改,所以每次在拿数据的时候都会上锁,传统的关系型数据库里就用到了很多的这种锁机制,如行锁,表锁,读锁和写锁等,都是在操作之前先上锁;Java中Synchronized和ReetranLock等独占锁就是悲观锁实现的。

悲观锁的实现方式:

悲观锁的实现是依赖于数据库提供的锁机制,流程如下:

1、修改记录前,对记录加上排它锁(exclusive locking)

2、如果加锁失败,说明这条数据正在被修改,那么当前查询要等待或者抛出异常,这由开发者决定

3、如果加锁成功,可以对这条数据修改了,事务完成解锁。

4、加锁修改期间,其他事务也想这条记录进行操作时,都要等待或直接抛出异常

在使用mysql innodb引擎实现悲观锁时,必须关闭mysql的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。

eg:

-- 0.开始事务
begin; 
-- 1.查询出商品库存信息
select quantity from items where id=1 for update;
-- 2.修改商品库存为2
update items set quantity=2 where id = 1;
-- 3.提交事务
commit;

使用select...for update会把数据锁住,MySQL InnoDB默认行级锁,行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住。

乐观锁:总是假设最好的situation,每次去拿数据时都believe别人不会修改,所以不会上锁,但是更新的时候会判断一下在此期间别人有没有去更新了这个数据(用版本号和CAS算法实现);乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write-condition机制,其实都是提供的乐观锁。

乐观锁的实现方式

乐观锁的实现不需要借助于数据库锁机制,只需要两个步骤,冲突检测和数据更新,其中一种典型的实现方法就是CAS(Compare and Swap)

CAS实现乐观锁

CAS是一种乐观锁实现方式,顾名思义就是先比较后更新。在对一个数据进行更新前,先持有这个数据原有值的备份。比如要将a=2更新为a=3,在进行更新前会比较此刻a是否为2,如果是2,才会进行更新操作,当多个线程尝试使用CAS同时更新一个变量时,只有一个线程能够成功,其余都是失败,失败的线程不会被挂起,而是被告知这次竞争失败,并且可以再次尝试。

-- 查询出商品库存信息,quantity = 3
select quantity from items where id=1
-- 修改商品库存为2
update items set quantity=2 where id=1 and quantity = 3;

在更新之前,先查询库存表中当前库存数,然后在做update时,以库存数作为一个修改条件。当进行提交更新的时候,判断数据库的当前库存数与第一次取出来的库存数进行比对,相等则更新,否则认为是过期数据,但是这种更新存在一个比较严重的问题,即ABA问题。

ABA问题

A线程取出库存数3,B线程取出库存数3,B线程先将库存数变为2,又将库存数变为3,A线程在进行更新操作时发现库存仍然是3,然后操作成功。尽管A线程操作时成功的,但是不能代表这个过程就是没问题的。

解决ABA问题的一个方法是通过一个顺序递增的version字段:

-- 查询出商品信息,version = 1
select version from items where id=1
-- 修改商品库存为2
update items set quantity=2,version = 2 where id=1 and version = 1;

在每次执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据版本号一致就可以执行修改操作并对版本号执行+1操作,否则执行失败,因为每次修改操作都会将版本号增加,所以不会出现ABA问题,还可以使用时间戳,因为时间戳自然具有顺序递增性。

乐观锁和悲观锁

乐观锁并不是真正的加锁,优点是效率高,缺点是更新失败的概率比较高;悲观锁依赖于数据库锁机制,更新失败的概率比较低,但是效率也低。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值