悲观锁和乐观锁

https://segmentfault.com/a/1190000022839728

悲观锁介绍

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中, 将数据处于锁定状态。比如如下场景中:

1、select status from t_goods where id = 1;

2、update t_goods set status=2 where id = 1;

如果不采用锁,并发情况下两个请求都会update成功,可能会导致一个商品被下单了两次。在上面的场景中,使用悲观锁的原理就是,当我们在查询出goods信息后就把当前的数据锁定,直到我们修改完毕后再解锁。那么在这个过程中,因为goods被锁定了,就不会出现有第三者来对其进行修改了。注:要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。

begin
//1.查询出商品信息
select status from t_goods where id=1 for update;
//2.修改商品status为2
update t_goods set status=2 where id = 1;;
//3.提交事务
commit;

与普通查询不一样的是,我们使用了select…for update的方式,这样就通过数据库实现了悲观锁。此时在t_goods表中,id为1的那条数据就被我们锁定了,其它事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。当我执行select status from t_goods where id=1 for update;后。我在另外的事务中如果再次执行select status from t_goods where id=1 for update;则第二个事务会一直等待第一个事务的提交,此时第二个查询处于阻塞的状态,但是如果我是在第二个事务中执行select status from t_goods where id=1;则能正常查询出数据,不会受第一个事务的影响。

使用select…for update会把数据给锁住,不过所以只有「明确」地指定主键或者指定了索引,MySQL 才会执行Row lock (只锁住被选取的数据)  ,否则MySQL 将会执行Table Lock (将整个数据表单给锁住)

例如:select status from t_goods where id=1 for update在where中指定了主键会锁行,select status from t_goods where status=1 for update没有指定主键,会锁表。

select status from t_goods where name="haha" for update (name列是索引),在where中指定了索引也会锁行

 

乐观锁介绍

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

使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现 方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现,version默认值为1。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们更新db的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新

 

如上图所示,如果更新操作顺序执行,则数据的版本(version)依次递增,不会产生冲突。但是如果发生有不同的业务操作对同一版本的数据进行修改,那么,先提交的操作(图中B)会把数据version更新为2,当A在B之后提交更新时发现数据的version已经被修改了,那么A的更新操作会失败。

db操作步骤:

1、select (status,status,version) from t_goods where id=1;

2、update t_goods set status = 2, version = version + 1 where id=1 and version=#{version};

所以当第一个请求更新时已经把version改成了2,第二个请求更新时发现where条件不匹配,所以不会更新成功。

 
 
乐观锁和悲观锁的使用场景和比较
1、乐观锁:适用于写比较少的情况下,冲突真的很少发生的时候。省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,调用方会不断进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适
2、悲观锁:适合写入比较多的情况下,如果出现大量的读取操作,每次读取的时候都会进行加锁,可能因为临键锁锁住大范围数据,降低了系统的吞吐量
悲观锁比较适合强一致性的场景,但效率比较低,特别是读的并发低。乐观锁则适用于读多写少,并发冲突少的场景。
posted @   MarkLeeBYR  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示