面试之悲观锁与乐观锁的概述

        首先我们先要知道,乐观锁与悲观锁是在高并发的情况下或者说是大数据量导入的时候使用的,也就是说当N多人,去访问一条数据或一张表数据的时候,就会涉及到乐观锁与悲观锁的问题,当然,如果你的访问量很少就不用考虑这个问题了

        然后,我们要知道它锁的是什么,锁的是数据,谁的数据?锁的是数据库中的数据,那就引出了我们现在的话题,锁数据库,有两种锁法,就是悲观锁和乐观锁。

        那锁住之后,上锁的数据就不能动,只能进行读的操作,不能进行写(增删改)的操作

举个例子:

比如在我的数据库中有一条数据,如下,

┊ id ┊ name ┊ version(版本号) ┊

┊ 1  ┊ 张三 ┊        1        ┊

注:version 是本来就有的,是我们自己建表的时候加的

        那么,当有用户(A)去访问这条数据的时候,他所拿到的版本号是 1 ,这个时候,用户(B)来了,也访问了这条数据,那么,他拿到的版本号也是 1 ,这就说明了,版本号在进行查询的时候,不做任何修改,但是,有一种情况。

        比如说我们在淘宝,京东等这种购物性的网站,有种活动,叫 "秒抢" 等等这类的活动,还是我们的 A B 两用户,当 A 和 B 都访问到(去看)商品的时候,都还有100件商品,但是!!在 用户A 还没点击付款按钮时, 用户B 按了付款的按钮,这个时候 用户B 看到的商品还有 99 件,而 用户A 看到的却是 100 件商品,

        那么我们,假设一个极端的例子,就剩下最后一件商品了,当 B 点了以后, A 看到的还是还有 1 件商品,那么 A 点下单的时候,将会是下单失败的情况,总不能让商品的数量为负数,所以我们必须要控制这种情况的发生,要有一个判断,怎么判断那?让我再给你说一遍,

        还是刚刚的那个例子,用户A 和 用户B 查询到数据后,都会携带着一个版本号,这个版本号与这条数据的版本一致,这个时候, 用户B 下单了,当然, 用户B 的操作是没有问题的,这个时候,这条数据的版本号(version) 就变成了 2 ,用户A 还是携带的版本号是 1 ,这个时候用户A 再去下单的时候,系统会发现,用户A 所携带的版本号与数据的版本号不一致,就不允许操作,就不发送这条 update 语句,就是说,如果你当前的版本号低于数据库的版本号就不让你进行修改操作,这就是乐观锁,这些都是通过程序来进行判断的,还有就是,版本号,只能加,不能减!!!这就是乐观锁,乐观锁就是,它会乐观的认为所有的更新都是允许的,但是,乐观锁也会有另外一种情况,是 死锁 的情况,这是一种极为极端的情况,还是刚刚我们说的那个例子, 用户A 与 用户B 去查了数据,用户B 比用户A 快,用户B 将版本号改为了2,用户A 没办法下单,那么A 就会去重新查询,再下单,但是 用户C 还是比 用户A 快,用户C 将版本号改为了3 , 那么照这样下去,用户A 永远对数据无法进行更新操作,当然了,我只是说会有这种情况的发生...

        然后我们说说悲观锁,悲观锁会悲观的认为所有的数据更改都是不合法的,它是依靠数据库的锁机制,如果说你的数据库没有这种锁机制,那么你想尽办法你也实现不了悲观锁,所以说它,依赖的是数据库的锁机制

        在我们通常用的 delete , update , selete等这些,它还有一个关键字,叫 lock(锁) , 当然每个数据库的都是不一样的,但是基本上都是支持这种锁机制的,我们就用 MySQL 来说吧,悲观锁还分 WRITE 和 READ 锁,它是执行, 'lock tables 表名 write' 或 'lock tables 表名 read' 来进行上锁的, 要注意的是,我们上完锁之后,我们再进行写的操作的时候,这张表会锁住,这张表就不允许任何人进行增删改的操作 ,悲观锁就是利用这种锁机制实现的,而且一锁就是一张表,这两个锁也是有分别的,这就有说到了线程的问题上,如果一个线程获得在一个表上的一个 READ 锁,该线程和所有其他线程只能从表中读。如果一个线程获得一个表上的一个 WRITE 锁,那么只有持锁的线程 READ 或 WRITE 表可以进行写操作,其他线程都被阻止

        当然了,能上锁当然也就可以解锁了,解锁也分两个, 'lock tables' 为释放当前线程锁定表。'unlock tables' 释放被当前线程持有的任何锁。还有一种情况,就是当线程发出另外一个 LOCK TABLES 时,或当服务器的连接被关闭时,当前线程锁定的所有表会自动被解锁。

        并且还不仅如此,还有一个问题,这个问题专属 MySQL, MySQL 有两种数据存储引擎(说白了就是两种存储办法),有一种引擎是不支持事务的,一种引擎是叫 InnoDB, 一个叫 MyISAM, 而这个 MyISAM 是不支持事务的, MyISAM 它强调的是性能,换句话说,你的 begin transaction 写了多少遍跟它没有一点关系,你想让他发生异常再回滚,不可能!!!,这种情况你只能到你的业务逻辑Service层去判断了...

就这,没了,该说的全说了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

槐序二十四

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

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

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

打赏作者

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

抵扣说明:

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

余额充值