A thorough understanding of how optimistic and pessimistic locking lock? Come, illustrations easy to understand!

This is an introductory optimistic and pessimistic locking lock introductory article. Designed to allow those who do not understand the white pessimistic locking and optimistic locking lock pessimistic figure out what is and what is optimistic locking. Unlike other articles, this article will be coupled with the corresponding illustrations so that we easier to understand. With this article, you will learn the following knowledge.

1

Lock (Lock)

Before introducing pessimistic locking and optimistic locking, let us see what is the lock.

Lock, can be seen everywhere in our lives, there is a lock on our door, we save money on safe lock, is used to protect our property safe.

The program also has a lock, when multiple threads modify the shared variable, we can modify the operation to lock (syncronized).

When a plurality of users to modify the same data table, we can lock to the data row (row locks). Therefore, the lock is actually control the execution order of multiple concurrent operations in order to ensure that changes in data security.

Also, the lock is a data security mechanisms and means to ensure that, while not specific to a particular technology. Optimistic and pessimistic locking lock is also true. Optimistic and pessimistic locking lock this introduction is based on the database level.

2

Pessimistic locking

Pessimistic locking ** (Pessimistic Concurrency Control) **, first saw it, I believe everyone will think this is a pessimistic lock. Yes, it is a pessimistic lock.

That this pessimism is reflected in what place? Pessimism is a negative emotion we humans, corresponds to pessimism locking, pessimistic locking think it was protected data is extremely unsafe, may change all the time, to get back a transaction pessimistic locking (understandable as a user), any other transaction can modify the data, can only wait for a lock to be released before they can perform.

Row lock the database, table locks, read locks, write locks and lock syncronized achieve are pessimistic locking.

Here to tell us about what's table and row locks the database, so some students to achieve pessimistic locking behind do not understand.

We often use the database is mysql, mysql most commonly used engine is Innodb, Innodb row lock is used by default. The row locks are index-based, so in order to add a row lock must be locked when the index hit, otherwise it will use table locks.

3

Optimistic locking

与悲观相对应,乐观是我们人类一种积极的情绪。乐观锁(Optimistic Concurrency Control)的“乐观情绪”体现在,它认为数据的变动不会太频繁。因此,它允许多个事务同时对数据进行变动。

但是,乐观不代表不负责,那么怎么去负责多个事务顺序对数据进行修改呢?

乐观锁通常是通过在表中增加一个版本(version)或时间戳(timestamp)来实现,其中,版本最为常用。

事务在从数据库中取数据时,会将该数据的版本也取出来(v1),当事务对数据变动完毕想要将其更新到表中时,会将之前取出的版本v1与数据中最新的版本v2相对比,如果v1=v2,那么说明在数据变动期间,没有其他事务对数据进行修改,此时,就允许事务对表中的数据进行修改,并且修改时version会加1,以此来表明数据已被变动。

如果,v1不等于v2,那么说明数据变动期间,数据被其他事务改动了,此时不允许数据更新到表中,一般的处理办法是通知用户让其重新操作。不同于悲观锁,乐观锁是人为控制的。

4

如何实现

经过上面的学习,我们知道悲观锁和乐观锁是用来控制并发下数据的顺序变动问题的。那么我们就模拟一个需要加锁的场景,来看不加锁会出什么问题,并且怎么利用悲观锁和乐观锁去解决。

场景:A和B用户最近都想吃猪肉脯,于是他们打开了购物网站,并且找到了同一家卖猪肉脯的>店铺。下面是这个店铺的商品表goods结构和表中的数据。

从表中可以看到猪肉脯目前的数量只有1个了。在不加锁的情况下,如果A,B同时下单,就有可能导致超卖。

悲观锁解决

利用悲观锁的解决思路是,我们认为数据修改产生冲突的概率比较大,所以在更新之前,我们显示的对要修改的记录进行加锁,直到自己修改完再释放锁。加锁期间只有自己可以进行读写,其他事务只能读不能写。

A下单前先给猪肉脯这行数据(id=1)加上悲观锁(行锁)。此时这行数据只能A来操作,也就是只有A能买。B想买就必须一直等待。

当A买好后,B再想去买的时候会发现数量已经为0,那么B看到后就会放弃购买。

那么如何给猪肉脯也就是id=1这条数据加上悲观锁锁呢?我们可以通过以下语句给id=1的这行数据加上悲观锁

  select num from goods where id = 1 for update;

下面是悲观锁的加锁图解

我们通过开启mysql的两个会话,也就是两个命令行来演示。
1、事务A执行命令给id=1的数据上悲观锁准备更新数据

这里之所以要以begin开始,是因为mysql是自提交的,所以要以begin开启事务,否则所有修改将被mysql自动提交。

2、事务B也去给id=1的数据上悲观锁准备更新数据

我们可以看到此时事务B再一直等待A释放锁。如果A长期不释放锁,那么最终事务B将会报错,这有兴趣的可以去尝试一下。

3、接着我们让事务A执行命令去修改数据,让猪肉脯的数量减一,然后查看修改后的数据,最后commit,结束事务。

我们可以看到,此时最后一个猪肉脯被A买走,只剩0个了。

4、当事务A执行完第3步后,我们看事务B中出现了什么

我们看到由于事务A释放了锁,事务B就结束了等待,拿到了锁,但是数据此时变成了0,那么B看到后就知道被买走了,就会放弃购买。

通过悲观锁,我们解决了猪肉脯购买的问题。

乐观锁解决

下面,我们利用乐观锁来解决该问题。上面乐观锁的介绍中,我们提到了,乐观锁是通过版本号version来实现的。所以,我们需要给goods表加上version字段,表变动后的结构如下:

使用乐观锁的解决思路是,我们认为数据修改产生冲突的概率并不大,多个事务在修改数据的之前先查出版本号,在修改时把当前版本号作为修改条件,只会有一个事务可以修改成功,其他事务则会失败。

A和B同时将猪肉脯(id=1下面都说是id=1)的数据查出来,然后A先买,A将id=1和version=0作为条件进行数据更新,即将数量-1,并且将版本号+1。

此时版本号变为1。A此时就完成了商品的购买。最后B开始买,B也将id=1和version=0作为条件进行数据更新,但是更新完后,发现更新的数据行数为0,此时就说明已经有人改动过数据,此时就应该提示用户重新查看最新数据购买。

下面是乐观锁的加锁图解

我们还是通过开启mysql的两个会话,也就是两个命令行来演示。

1、事务A执行查询命令,事务B执行查询命令,因为两者查询的结果相同,所以下面我只列出一个截图。

此时A和B均获取到相同的数据

2、事务A进行购买更新数据,然后再查询更新后的数据。

我们可以看到事务A成功更新了数据和版本号。

事务B再进行购买更新数据,然后我们看影响行数和更新后的数据

可以看到最终修改行数为0,数据没有改变。此时就需要我们告知用户重新处理。

5

优缺点

下面我们介绍下乐观锁和悲观锁的优缺点以便我们分析他们的应用场景,这里我只分析最重要的优缺点,也是我们要记住的。

悲观锁

  • 优点:悲观锁利用数据库中的锁机制来实现数据变化的顺序执行,这是最有效的办法

  • 缺点:一个事务用悲观锁对数据加锁之后,其他事务将不能对加锁的数据进行除了查询以外的所有操作,如果该事务执行时间很长,那么其他事务将一直等待,那势必影响我们系统的吞吐量。

乐观锁

  • 优点:乐观锁不在数据库上加锁,任何事务都可以对数据进行操作,在更新时才进行校验,这样就避免了悲观锁造成的吞吐量下降的劣势。

  • 缺点:乐观锁因为是通过我们人为实现的,它仅仅适用于我们自己业务中,如果有外来事务插入,那么就可能发生错误。

6

应用场景

悲观锁:因为悲观锁会影响系统吞吐的性能,所以适合应用在写为居多的场景下。

乐观锁:因为乐观锁就是为了避免悲观锁的弊端出现的,所以适合应用在读为居多的场景下

最后

入门文章就先讲到这里,想要更进一步学习可以看这个文档。

我们程序员需要学习很多东西,而学到的知识点,都是钱(因为技术人员大部分情况是根据你的能力来定级、来发薪水的),技多不压身。

附上我的Android核心技术学习大纲,获取相关内容来GitHub:https://github.com/Meng997998/AndroidJX

发布了130 篇原创文章 · 获赞 61 · 访问量 2万+

Guess you like

Origin blog.csdn.net/Aerfa789/article/details/104538164
Recommended