大白话讲清楚悲观锁和乐观锁的区别

本文详细介绍了在数据库中为保证数据一致性而使用的悲观锁和乐观锁概念。悲观锁通过数据库的排他锁实现,确保在事务处理过程中数据不被修改,适合并发写入频繁的场景。而乐观锁则依赖版本字段,在更新时检查版本号,适用于读多写少的场景。两种锁机制各有优劣,适用于不同的并发环境。
摘要由CSDN通过智能技术生成

假设

有这么一个场景,库存表中一条产品库存数为50,如果我们需要增加20的库存数,则需要先查出当前库存数,在业务层上做新增库存数和当前库存数相加后再进行update的更新。
但是库存数在生产环境中他是浮动的,当我们查询完当前库存数,在业务层做库存相加运算逻辑时,及有可能其他业务在这时下单并进行了库存的扣减,从而导致最后更新库存数不准确。
为了解决以上类似的场景问题,因此提出了悲观锁乐观锁的概念,目的都是为了数据在查询出来到修改,数据始终保持一致性。

悲观锁

悲观锁的实现需要依靠使用数据库的排他锁(for update),并且需要关闭mysql数据库的自动提交属性,因为mysql默认使用autocommit模式,也就是说,当你执行一个更新操作后,mysql会立刻将结果进行提交。


悲观锁执行流程:

//0.先把MYSQL自动提交改为0
set autocommit=0;

//1.开始事务
begin;

//2.先在库存中心查出id为1的库存数 #假设值为50
select Inventory from Inventory_center where id=1 for update;(加了排他锁的查询)

//3.对id为1的库存增加20库存数
update Inventory_center set inventory =70 where id=1;

//4.提交事务
commit;


上面的查询语句中,我们使用了select…for update的方式,这样就通过开启排他锁的方式实现了悲观锁。此时在Inventory_center表中,id为1的那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改,直到我们更新完数据。
需要注意排他锁需要用主键id为判断,如果用别的条件,会使锁定整张表。锁表的消耗小,但锁表并发会受到限制。
Select * from 表名 where 主键id=1 for update;(锁行不锁表)
Select * from 表名 where 主键id=不存在的值 for update;(不会使用锁)
Select * from 表名 where name=’jiani’for update;(没有用主键作为判断条件会锁住整张表)

乐观锁

乐观锁的实现需要在数据表里加个version字段,当update更新时 version+1,乐观锁每次更新数据时都需要比对version字段是否与查询时一致,一致则更新成功,不一致则说明数据在这期间被其他线程修改,更新则失败。


乐观锁执行流程:

//0.查询id为1的库存数和当前version值。
select Inventory,version from Inventory_center where id=1
#假设查询结果为Inventory=50,version=5

//1.更新库存数,库存数+20 #并比对version值是否与查询时一致。
int 1= update Inventory_center set Inventory=70,version=version+1 where id=1 and version=5;

//2.更新失败则可采用递归的方式重新更新。
if (int =0){ 递归重新更新 }


结言

最后说下两种锁各自的使用场景,悲观锁适合用于并发写入多、临界区代码复杂、竞争激烈等场景,这种场景下悲观锁可以避免大量的无用的反复尝试等消耗。乐观锁适用于大部分是读取,少部分是修改的场景,也适合虽然读写都很多,但是并发并不激烈的场景。在这些场景下,乐观锁不加锁的特点能让性能大幅提高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值