乐观锁与悲观锁

本文记录一下关于乐观锁与悲观锁的讨论,为了防止遗忘,故而记录一下,各位路过若发现有不对的地方,希望帮忙指出。


一、乐观锁和悲观锁有什么区别

答:
乐观锁和悲观锁是两种不同的并发控制的机制,它们的区别主要在于对数据修改的假设和处理方式:
悲观锁是假设数据很容易被其他事务修改,所以在访问数据的时候就会加锁,防止其他事务对数据进行修改,直到自己的事务结束才会释放锁。这样可以保证数据的一致性,但是会降低并发性能,因为其他事务只能等待锁的释放。
乐观锁是假设数据很少被其他事务修改,所以在访问数据的时候不会加锁,而是在更新数据的时候才会检查数据是否被其他事务修改过,如果是,就会回滚事务,否则就会提交事务。这样可以提高并发性能,但是会增加回滚的可能性,因为可能存在多个事务同时更新同一条数据。


二、关于乐观锁与悲观锁的例子

假设有一个银行账户,有两个用户A和B同时要对账户进行操作,A要存款100元,B要取款50元。
如果使用悲观锁,那么A和B都会在访问账户的时候加锁,防止其他事务对数据进行修改,直到自己的事务结束才会释放锁。这样,只有一个用户可以操作账户,另一个用户只能等待。例如,如果A先访问账户,那么B就不能访问,直到A存款完成并释放锁。同理,如果B先访问账户,那么A就不能访问,直到B取款完成并释放锁。这样可以保证账户的余额不会出错,但是会降低并发性能,因为A和B都要等待对方的操作。
如果使用乐观锁,那么A和B都不会在访问账户的时候加锁,而是在更新账户的时候才会检查数据是否被其他事务修改过,如果是,就会回滚事务,否则就会提交事务。这样,两个用户都可以同时操作账户,但是可能会导致更新失败。例如,如果A和B同时访问账户,假设账户的余额是1000元,并且有一个版本号是1。然后A和B都根据自己的操作计算出新的余额和版本号,A的新余额是1100元,新版本号是2;B的新余额是950元,新版本号也是2。然后A和B都尝试更新账户,但是只有一个用户可以成功。例如,如果A先更新账户,那么他会检查当前的版本号是否和自己之前读取的一致,如果一致,就会更新余额和版本号,并提交事务。这时候,账户的余额变成了1100元,版本号变成了2。然后B再更新账户,他也会检查当前的版本号是否和自己之前读取的一致,但是发现不一致了(因为被A修改过了),所以就会回滚事务,并重新读取账户的数据。这时候,B会发现账户的余额是1100元,版本号是2。然后B再根据自己的操作计算出新的余额和版本号,B的新余额是1050元,新版本号是3。然后B再尝试更新账户,这次就会成功了。这样可以提高并发性能,但是会增加回滚的可能性,因为可能存在多个用户同时更新同一个账户。


三、疑问解答

1、为什么说乐观锁提高了并发性能?

问题描述:从这个例子上来说,乐观锁并没有提高并发性能啊,你看,在悲观锁中,a和b操作的时候,如果a先操作了,那么,b只需要等待a完成就可以操作。但是在乐观锁例子中,a和b操作的时候,如果a先操作了,那么b因为乐观锁也可以操作,但是会发生事务回滚,这样b还要重新操作一次。这两个方式对比一下,乐观锁不是相当于多了一次回滚事务的操作吗,为什么说并发性能还提升了

答:乐观锁和悲观锁的并发性能并不是只取决于一个例子,而是要看整体的情况。在这个例子中,乐观锁确实会导致B的事务回滚,这样看起来好像比悲观锁多了一次操作。但是,你要考虑到,这个例子是假设A和B同时访问账户,这种情况并不是很常见,因为数据很少被其他事务修改,这是乐观锁的基本假设。如果A和B不是同时访问账户,而是有一定的时间间隔,那么乐观锁就不会发生回滚,而悲观锁仍然会发生阻塞。例如,如果A先访问账户,然后B在A提交事务后一秒再访问账户,那么在乐观锁中,B就可以直接更新账户,不会回滚;而在悲观锁中,B仍然要等待A释放锁,才能访问账户。这样,乐观锁就比悲观锁节省了等待的时间。所以,乐观锁和悲观锁的并发性能要看整体的数据修改频率和事务执行时间,不能只看一个特殊的例子。


2、悲观锁释放锁足够快就可以?

问题描述:按照你说的,b在a提交事务之后一秒再访问账户,在乐观锁中,b可以直接更新账户,但是悲观锁中,b需要等待a释放锁,才可以。那么,前面已经说了,在一秒之前,a已经提交事务了,那么悲观锁中,a提交事务之后,他不会释放锁吗?a提交事务之后立刻释放锁,那么乐观锁和悲观锁不就相当于一样了吗

答:悲观锁中,A提交事务之后,他会释放锁,这是没错的。但是,你要考虑到,A的事务不一定只有一条更新语句,可能还有其他的操作,比如查询、计算、判断等。这些操作都会占用一定的时间,而在这段时间内,A都会持有锁,阻塞其他事务的访问。而在乐观锁中,A不会持有锁,只有在更新数据的时候才会检查版本号。所以,乐观锁和悲观锁的区别不仅在于更新数据的时候是否回滚或阻塞,还在于访问数据的时候是否加锁或不加锁。


3、对于悲观锁来说,访问数据也会加锁?

问题描述:所以实际上,悲观锁的重点在于,所有操作都会加锁,甚至于查询,计算,判断这些,但是乐观锁中,只有数据更新才会加锁,访问数据是不会加锁的,可以这么理解吧

答:差不多是这样的,但是要注意,乐观锁中,数据更新也不会加锁,而是会检查版本号。加锁和检查版本号是两种不同的方式,加锁是一种排他的方式,只允许一个事务访问数据,其他事务要等待;检查版本号是一种非排他的方式,允许多个事务同时访问数据,但是只有一个事务可以更新数据,其他事务要回滚。


4、如果一个表死锁,是不是说明用了悲观锁?

问题描述:乐观锁是不是不会发生死锁,比如当某一个表陷入死锁了,那是不是可以认为它用的悲观锁

答:乐观锁是不会发生死锁的,因为乐观锁不会加锁,而死锁是由于多个事务互相等待对方释放锁而造成的。比如,如果有两个事务A和B,A要更新表T1和T2,B要更新表T2和T1,如果使用悲观锁,那么可能发生以下的情况:
A先更新表T1,加上排他锁。
B先更新表T2,加上排他锁。
A再更新表T2,发现被B锁住了,就等待B释放锁。
B再更新表T1,发现被A锁住了,就等待A释放锁。
这样,A和B就陷入了死锁,无法继续执行。
如果使用乐观锁,那么不会发生这种情况,因为A和B都不会加锁,而是在更新数据的时候检查版本号。例如:
A先更新表T1,检查版本号是否一致,如果一致,就更新数据,并增加版本号。
B先更新表T2,检查版本号是否一致,如果一致,就更新数据,并增加版本号。
A再更新表T2,检查版本号是否一致,发现不一致了(因为被B修改过了),就回滚事务,并重新读取数据。
B再更新表T1,检查版本号是否一致,发现不一致了(因为被A修改过了),就回滚事务,并重新读取数据。
这样,A和B就不会陷入死锁,而是可以重新执行事务。

四、总结

这个银行的小例子与后面的几个问题,基本帮我初步理解了悲观锁与乐观锁的概念,如果还有相关的,后续可能还会补充。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值