MySQL面试题

悲观锁与乐观锁

2019-03-10  本文已影响38人  宋雾代

去参加企业面试,技术面当中关于数据库这个问题算是高频问题了,所以在这篇文章中我们一起来搞清楚这两个概念。

什么是锁

我们知道数据库是用来存储数据的,传统的SQL数据库的内容存储在数据库库表中,一条数据就是数据库的一行。

数据库同时提供给多个线程或进程访问,用来做数据库内容的增删改查,当多个进程或线程对同一条数据进行操作时,就可能出现如下问题:

丢失更改:

假如存在以下线程:

线程1从数据库取出数据并将值加1存回数据库。

线程2从数据库取出数据并将值减1存回数据库。

假设当时数据库值为1,两条线程同时执行,则有1号线程执行结果为2,2号线程执行结果为0,无论数据库存哪个结果,都会丢失另一个线程的执行结果。

脏读:

线程1修改了数据,随后线程2又读出该数据,但线程1因为某些原因取消了对数据的修改,数据恢复原值,此时线程2得到的数据就与数据库内的数据产生了不一致 。

不可重复读:

线程1读取数据,随后线程2读出该数据并修改,此时线程1再读取数据时发现前后两次的值不一致 。

可以看出不加任何控制的并发执行可能出现任何无法预料的结果,所以需要对数据库修改进行限制,在一段时间内禁止用户做某些操作以避免产生数据不一致,这就是锁。

悲观锁

它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度(悲观),因此,在整个数据处理过程中,将数据处于锁定状态。 悲观锁的实现,往往依靠数据库提供的锁机制 (也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

执行过程

在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。

如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。 具体响应方式由开发者根据实际需要决定。

如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。

其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。

优点与不足

悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载;还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数据。

乐观锁

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

实现方式

相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。

数据版本,为数据增加的一个版本标识。当读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为是过期数据。

上一篇 下一篇

猜你喜欢

热点阅读