mysql 乐观锁 高并发_高并发下悲观锁与乐观锁的选择问题

无论是悲观锁还是乐观锁,其实都是并发控制的一种思想,并不仅仅局限于数据库,具体如何选择乐观锁和悲观锁是根据业务场景来的。

悲观锁:

一般情况下,我们使用的悲观锁就是在数据库层面增加一个排它锁,加锁成功就可以修改数据然后提交事务,事务提交成功解锁,失败就说明数据正在被修改。如果你使用mysql的innodb的话,要注意set autocommit=0关闭mysql自动提交属性,因为mysql默认使用autocommit模式,就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交,另外还要注意锁的级别,默认innodb是使用行级锁,但是行级锁是基于索引的,如果你这条sql没用索引,那么mysql就会使用表级锁锁表了。

优缺点:

悲观锁是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会。另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载。还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数据。

乐观锁:

乐观锁其实就是假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。

一般直接写在代码逻辑层就可以了,相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制,通常采用一个version版本号或时间戳来实现。使用版本号时,可以在数据初始化时指定一个版本号,每次对数据的更新操作都对版本号执行+1操作。并判断当前版本号是不是该数据的最新的版本号。如:

1.查询出商品信息

select (status,version) from t_goods where id=#{id}

2.根据商品信息生成订单

3.修改商品status为2

update t_goods

set status=2,version=version+1

where id=#{id} and version=#{version};

优缺点:

乐观锁认为数据竞争的概率是很小的,因此,尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。但如果直接简单这么做,还是有可能会遇到不可预期的结果,例如两个事务都读取了数据库的某一行,经过修改以后写回数据库,这时就遇到了问题。

乐观锁存在失效的情况,属小概率事件,需要多个条件共同配合才会出现。如:

应用采用自己的策略管理主键ID。如,常见的取当前ID字段的最大值+1作为新ID。

版本号字段 version 默认值为 0 。

用户A读取了某个记录准备修改它。该记录正好是ID最大的记录,且之前没被修改过,version 为默认值 0。

在用户A读取完成后,用户B恰好删除了该记录。之后,用户C又插入了一个新记录。

此时,阴差阳错的,新插入的记录的ID与用户A读取的记录的ID是一致的, 而版本号两者又都是默认值 0。

用户A在用户C操作完成后,修改完成记录并保存。由于ID、version均可以匹配上,因此用户A成功保存。但是,却把用户C插入的记录覆盖掉了。

乐观锁此时的失效,根本原因在于应用所使用的主键ID管理策略, 正好与乐观锁存在极小程度上的不兼容。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值