悲观锁和乐观锁的详细分析

匿名 (未验证) 提交于 2019-12-02 23:48:02

使用场景举例:我们以mysql的存储引擎 InnoDB为例(如果不采用锁机制)

因此在上述情况中我们可以采用悲观锁

在上面的情况中,商品被查询出来,有一个处理订单的过程,我们可以使用悲观锁机制,当我们查出这个goods信息后,就把当前的数据锁定起来,直到我们修改完毕再解锁,所以在我们处理该goods的时候,就避免了第三者来修改

下面来简单演示一下吧

for update;

注意:这里有个问题在是使用悲观锁的时候,如果第一个事务没有commit我们是不能进行该相同数据的写操作的,但是读操作分两种情况,在事务中,只有SELECT ... FOR UPDATE 或LOCK IN SHARE MODE 同一笔数据时会等待其它事务结束后才执行,一般SELECT ... 则不受此影响。拿上面的实例来说,当我执行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;则能正常查询出数据,不会受第一个事务的影响。

补充:MySQL select…for update的Row Lock与Table Lock

上面我们提到,使用select…for update会把数据给锁住,不过我们需要注意一些锁的级别,MySQL InnoDB默认Row-Level Lock,所以只有「明确」地指定主键(id),MySQL 才会执行Row lock (只锁住被选取的数据) ,否则MySQL 将会执行Table Lock (将整个数据表单给锁住)。

如果明确有主键,没有数据,则没有lock

如果没有主键,采用table lock;

console2 :处于阻塞状态,如果console1长时间不提交,他就会报错,说明这里对全表进行了上锁

如果没有定义主键,采用table lock;

console1:正常查询

console2:查询被阻塞,说明表被console1锁住了

以上就是关于数据库主键对MySQL锁级别的影响实例,需要注意的是,除了主键外,使用索引也会影响数据库的锁定级别

谈到了MySQL悲观锁,但是悲观锁并不是适用于任何场景,它也有它存在的一些不足,因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。如果加锁的时间过长,其他用户长时间无法访问,影响了程序的并发访问性,同时这样对数据库性能开销影响也很大,特别是对长事务而言,这样的开销往往无法承受。所以与悲观锁相对的,我们有了乐观锁,具体参见下面介绍

乐观锁介绍:

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

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

使用举例:以MySQL InnoDB为例

还是拿之前的实例来举:商品goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品status为1。假设商品的id为1

输出结果如下:

这样我们就简单实现了一个乐观锁机制!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!