Mysql数据库锁之---表级锁、行级锁、悲观锁、乐观锁、间隙锁GAP、死锁等简单介绍

系统管理员 2022-05-17 09:11 317阅读 0赞

目录

一、数据库默认加的锁

二、表级锁与行级锁

  1. 表级锁
  2. 行级锁

三、乐观锁与悲观锁

  1. 乐观锁
  2. 悲观锁

四、间隙锁GAP

五、死锁

总结


  1. Mysql中有:排它锁,共享锁,表锁,页锁,间隙锁,意向排它锁,意向共享锁,行锁,读锁,写锁,乐观锁,悲观锁,死锁...等关于锁的名词我们是耳听目染,但这些锁名词是什么?怎么用?

本文,以Mysql数据库为例,在MyISAMInnoDB引擎下,梳理 表级锁与行级锁乐观锁与悲观锁间隙锁GAP、死锁

之后如果有补充也会在该本章内继续添加。

一、数据库默认加的锁

  1. 在并发情况下,为了尽可能的保证数据的正确性,故有了锁这个概念。
  2. 很多开发者都对锁概念有了解,但在平时的开发中,感觉并没有使用到"锁",但是程序依然可以正确运行。
  3. 这是因为Mysql的数据库**隐式**自动对一些语句加锁了。

InnDB:对于UPDATE、DELETE、INSERT语句,自动给涉及数据集加排他锁(X)

  1. **MyISAM:**执行**SELECT**语句前,会**自动**给涉及的所有表加**读锁**。对于UPDATEDELETEINSERT等,会**自动**给涉及的表加**写锁**

二、表级锁与行级锁

锁粒度,我们将锁分为了:表级锁、行级锁

表级锁

开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低

行级锁

开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高

  1. **InnDB**:
  2. (1) 行锁和表锁都支持,但是!只有通过**索引条件**检索数据**才使用行级锁**,否则,InnoDB将使用**表锁。**

(2) 不支持查询和插入操 作的并发进行。

MyISAM

  1. (1) 只支持表锁。
  2. (2) 支持查询和插入操作的**并发**进行。可以通过系统变量concurrent\_insert来指定哪种模式,在**MyISAM**中它默认是:如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从**表尾**插入记录。

表级锁 分为两种模式:

  • 表读锁(Table Read Lock)
  • 表写锁(Table Write Lock)

Javaç¼ç¨ââæ°æ®åºä¸¤å¤§ç¥å¨ï¼ç´¢å¼åé

  1. 读读不阻塞:当前用户在读数据,其他的用户也在读数据,不会加锁
  2. 读写阻塞:当前用户在读数据,其他的用户**不能修改当前用户读的数据**,会加锁!
  3. 写写阻塞:当前用户在修改数据,其他的用户**不能修改当前用户正在修改的数据**,会加锁!

也就是说:读锁和写锁是互斥的,读写操作是串行

参考资料

  • dev.mysql.com/doc/refman/…—官方手册
  • ourmysql.com/archives/56…—-几个参数说明

三、乐观锁与悲观锁

乐观锁

概念

  1. 乐观锁是一种**思想**!其核心思想是:这个模式没有从数据库加锁!
  2. "锁"概念的实现是:通过一些方式来判断数据库数据是否变动,如果未变动,则修改数据;如果发现数据变动,则不修改数据。

例:

  1. 我们为某表添加一个版本字段version。修改一次数据,version +1。如下图

Javaç¼ç¨ââæ°æ®åºä¸¤å¤§ç¥å¨ï¼ç´¢å¼åé

  1. (1) 张三和李四同时查出上面的数据。
  2. (2) 张三先做出修改:
  • update A set Name=lisi,version=version+1 where ID=#{1} and version=#{1}

    注:判断之前查询到的version与现在的数据的version进行比较,同时会更新version字段+1

    (3) 此时,数据为:

Javaç¼ç¨ââæ°æ®åºä¸¤å¤§ç¥å¨ï¼ç´¢å¼åé

  1. (4) 李四后又修改:
  • update A set Name=lisi,version=version+1 where ID=#{1} and version=#{1}

    但此时失败了!因为当前数据库中的版本跟查询出来的版本不一致

这样便实现了”锁”机制的实现。这种便是“乐观锁”思想。它是一种思想!

悲观锁

使用

悲观锁的话其实很简单(手动加行锁就行了)

  • select * from xxxx for update

在select 语句后边加了 for update相当于加了排它锁(写锁),加了写锁以后,其他的事务就不能对它修改了!需要等待当前事务修改完之后才可以修改.

也就是说,如果张三使用select … for update,李四就无法对该条记录修改了~

参考资料

  • zhuanlan.zhihu.com/p/31537871—-什么是悲观锁和乐观锁
  • www.zhihu.com/question/27…—-乐观锁和 MVCC 的区别?

四、间隙锁GAP

概念

  1. 当我们**用范围条件检索数据,**并请求共享或排他锁时,InnoDB会给**符合范围条件的已有数据记录的索引项加锁**;

对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”。InnoDB也会对这个“间隙”加锁

注意!间隙锁只能在Repeatable read隔离级别下使用~

例:

  1. 假如emp表中只有101条记录
  • Select * from emp where empid > 100 for update;

nnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁

目的

  • 为了防止幻读:在一个事务未提交前,其他并发事务不能插入满足其锁定条件的任何记录

五、死锁

概念

  1. 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

发生条件

  1. **1)互斥条件:**指进程对所分配到的资源具有排它性。即在一段时间内该资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

2)请求和保持条件:指进程已经保持(持续获得)至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞(只能等其他进程用完再用),但又对自己已获得的其它资源保持不放。

3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。(感觉和 互斥条件 差不多呢?)

4)环路等待条件:即{P0,P1,P2,P3}进程中,P0等待P1占用的资源;P1等待P2占用的资源,P3正在等待P0占用的资源。然后就这么等下去了….前三个为具条件,第四个为发生诱因!

解决方案

  • 1)以固定的顺序访问表和行。将两个事务的sql顺序调整为一致,来避免死锁。

  • 2)大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。

  • 3)一次锁定。在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。
  • 4)降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁。
  • 5)为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大。

参考资料

  • hedengcheng.com/?p=771#_Toc…
  • www.cnblogs.com/LBSer/p/518…
  • https://blog.csdn.net/joejames/article/details/37960873

总结

关于表锁

  • 在MyISAM存储引擎中,当执行SQL语句的时候是自动加的。
  • 在InnoDB存储引擎中,如果没有使用索引,表锁也是自动加的。

所以 其实我们程序员是很少关心它

关于行锁

InnoDB支持行锁:

  • 共享锁—读锁—S锁
  • 排它锁—写锁—X锁

在默认的情况下,select是不加任何行锁的~事务可以通过以下语句显示给记录集加共享锁或排他锁。

  • 共享锁(S):SELECT * FROM table_name WHERE … LOCK IN SHARE MODE
  • 排他锁(X):SELECT * FROM table_name WHERE … FOR UPDATE

关于乐观锁与悲观锁

  • 乐观锁其实是一种 思想!它不加锁!一般是添加version字段来验证数据是否异常。如果发现数据异常,则不更新(回滚)
  • 悲观锁是 添加行锁!认为数据库会发生并发冲突,直接上来就把数据锁住,其他事务不能修改,直至提交了当前事务

关于间隙锁GAP

  1. InnoDB下,Repeatable read隔离级别配合GAP间隙锁来**避免幻读**!

参考资料

  • zhuanlan.zhihu.com/p/29150809—Mysql锁总结
  • blog.csdn.net/mysteryhaoh…—MySQL学习之——锁(行锁、表锁、页锁、乐观锁、悲观锁等)
  • segmentfault.com/a/119000001…—MySQL InnoDB引擎锁的总结

本文参考:https://www.toutiao.com/i6583941335516971524/

发表评论

表情:
评论列表 (有 0 条评论,317人围观)

还没有评论,来说两句吧...

相关阅读