数据库的乐观锁和悲观锁

目录

悲观锁

乐观锁

对比与选择


在并发的环境下,需要用乐观锁和悲观锁来控制数据的准确性。

最终库存数量为4,但其实要是3才对,这就是并发环境下,没有做好并发控制的情况。

悲观锁

为了避免数据被同时修改,对一条数据进行修改前进行上锁,直到自己修改完,提交事务,才释放锁。这有点类似Java中的同步机制,对修改共享数据的代码进行同步,同一时间只能一个人修改来保证数据的准确性。

这种总是假设最坏的情况,每次读取数据的时候都默认其他线程会更改数据,因此需要进行加锁操作,当其他线程想要访问数据时,都需要阻塞挂起,这种具有强烈的排他性,比较霸道的称为悲观锁。

实现方案:通过使用select...for update语句, 执行该语句后,会在表上加持行锁,一直到事务提交,解除行锁。

//0.开始事务
begin; 


//1.查询出商品信息
select stockCount from seckill_good where id=1 for update;


//2.修改商品stockCount减一
update seckill_good set stockCount=stockCount-1 where id=1;


//3.提交事务
commit;

在对id = 1的记录修改前,先通过for update的方式进行加锁,然后再进行修改。

同一时间只有一个线程可以开启事务并获得id=1的锁,其它的事务必须等本次事务提交之后才能执行。

注意:

使用select_for_update,另外一定要写在事务中,加锁要么全执行,要么全不执行。

要使用悲观锁,必须关闭mysql数据库中自动提交的属性,命令set autocommit=0

乐观锁

乐观锁是相对悲观锁而言的,他不会加锁,是在数据进行提交更新的时候进行检测冲突,如果没有冲突,则正常更新数据,有冲突就看程序员如何处理,看是否回滚等。

主要实现方案:版本号+条件查询、CAS

版本号+条件查询

//1.查询出要下单商品的信息        
select stockCount, version from good where id=1;           

//2.修改要下单商品的库存数量
update good set stockCount=stockCount-1, version = version+1 where id=1, version=version

id为1,version为3,stockCount为5

同一时刻,一个用户成功修改库存为4,version为4;其他用户还是拿着id为1,version为3的条件取更新库存数量就不能更新成功了。这时可以让其他失败的用户重新下单,就会拿着id为1,version为4的条件更新库存数量为3。。。美好的结果

这样就算有多个用户同时下单同一个商品,在同一时刻,也只有一个能成功修改。

对比与选择

乐观锁的方式,在高并发时,只有一个线程能执行成功,会造成大量的失败,这给用户的体验显然是很不好的。并发冲突(冲突是指两个请求同时需要修改共享数据)少时可以用。

乐观锁没有加锁,效率是高的。

乐观锁如果有人在你之前更新了,你的更新应当是被拒绝的,可以让用户从新操作。悲观锁则会等待前一个更新完成再执行下一个更新。这也是区别。

响应效率:如果需要非常高的响应速度,建议采用乐观锁方案,成功就执行,不成功就失败,不需要等待其他并发去释放锁。乐观锁并未真正加锁,效率高。一旦锁的粒度掌握不好,更新失败的概率就会比较高,容易发生业务失败。


冲突频率:如果冲突频率非常高(就是写多),建议采用悲观锁,保证成功率。冲突频率大,选择乐观锁会需要多次重试才能成功,代价比较大。


重试代价:如果重试代价大,建议采用悲观锁。悲观锁依赖数据库锁,效率低。更新失败的概率比较低。

读写次数:读请求多使用乐观锁,写操作多使用悲观锁。
 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺着听Jay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值