按锁思想分类
  1. 悲观锁
  • 优点:适合在写多读少的并发环境中使用,虽然无法维持非常高的性能,但是在乐观锁无法提更好的性能前提下,可以做到数据的安全性
  • 缺点:加锁会增加系统开销,虽然能保证数据的安全,但数据处理吞吐量低,不适合在读书写少的场合下使用
  1. 乐观锁
  • 优点:在读多写少的并发场景下,可以避免数据库加锁的开销,提高DAO层的响应性能,很多情况下ORM工具都有带有乐观锁的实现,所以这些方法不一定需要我们人为的去实现。
  • 缺点:在写多读少的并发场景下,即在写操作竞争激烈的情况下,会导致CAS多次重试,冲突频率过高,导致开销比悲观锁更高。
  • 实现:数据库层面的乐观锁其实跟CAS思想类似, 通数据版本号或者时间戳也可以实现。
按锁粒度分类
  1. 表锁

表锁是指对一整张表加锁,一般是 DDL 处理时使用

表锁由 MySQL Server 实现,表级锁更适合于以查询为主,并发用户少,只有少量按索引条件更新数据的应用,如Web 应用

  • 优点:开销小,加锁快;不会出现死锁;
  • 缺点:锁定粒度大,发生锁冲突的概率最高,并发度最低。
  1. 页锁:介于表锁和行锁之间。BDB 存储引擎采用的是页面锁(page-level locking)

  2. 行锁

    行锁则是锁定某一行或者某几行,或者行与行之间的间隙。

行锁则是存储引擎实现,行级锁更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统

  • 优点:锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
  • 缺点:开销大,加锁慢;会出现死锁;
InnoDB行锁类型
  1. 标准
  • 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁
  • 排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。

数据库并发场景主要有三种:

  • 读-读:不存在任何问题,也不需要并发控制
  • 读-写:有隔离性问题,可能遇到脏读,幻读,不可重复读
  • 写-写:可能存更新丢失问题,比如第一类更新丢失,第二类更新丢失
  1. 更细粒度
  • 共享锁(S)
  • 排他锁(X)
  • 意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的 IS 锁。
  • 意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的 IX 锁。

一致性(非)锁定读

一致性非锁定读:

一致性非锁定读由MVCC(多版本并发控制)实现。MVCC其实就是在每一行记录后面增加两个隐藏列,记录创建版本号和删除版本号,而每一个事务在启动的时候,都有一个唯一的递增的版本号

详细可参考前文《深入理解MySQL系列之redo log、undo log和binlog》

一致性锁定读:

SELECT ... FOR UPDATE //加X锁

SELECT ... LOCK IN SHARE MODE //加S锁

锁的算法

行锁的三种算法:

  • Record Lock:当个行记录上的锁
  • Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
  • Next Key Lock:Gap Lock + Record Lock ,锁定一个范围,并且锁定记录本身(只有REPEATABLE READ隔离级别有)

在默认事务隔离级别(REPEATABLE READ)下,InnoDB采用Next Key Lock解决幻读(Phantom Problem)。对一个范围加X锁,从而这个范围不允许插入,所以避免了幻读。

此外,还可以用Next key lock实现唯一性检查。如下,用户通过索引查询一个值,并对该行加一个S Lock;如果行不存在,锁定一个范围,新插入值也是唯一的。

SELECT * FROM TABLE WHERE COL = xxx LOCK IN SHARE MODE;
// 如果没有找到任何行
INSERT INTO TABLE VALUES(...)

间隙锁加锁原则:

  • 1、加锁的基本单位是 NextKeyLock,是前开后闭区间。
  • 2、查找过程中访问到的对象才会加锁。
  • 3、索引上的等值查询,给唯一索引加锁的时候,NextKeyLock退化为行锁。
  • 4、索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,NextKeyLock退化为间隙锁。
  • 5、唯一索引上的范围查询会访问到不满足条件的第一个值为止。
自增锁

AUTOINC 锁又叫自增锁(一般简写成 AI 锁),是一种表锁,当表中有自增列(AUTOINCREMENT)时出现。

当插入表中有自增列时,数据库需要自动生成自增值,它会先为该表加 AUTOINC 表锁,阻塞其他事务的插入操作,这样保证生成的自增值肯定是唯一的。AUTOINC 锁具有如下特点:

AUTO_INC 锁互不兼容,也就是说同一张表同时只允许有一个自增锁;

自增值一旦分配了就会 +1,如果事务回滚,自增值也不会减回去,所以自增值可能会出现中断的情况。

显然,AUTOINC 表锁会导致并发插入的效率降低,为了提高插入的并发性,MySQL 从 5.1.22 版本开始,引入了一种可选的轻量级锁(mutex)机制来代替 AUTOINC 锁,可以通过参数 innodbautoinclockmode 来灵活控制分配自增值时的并发策略。具体可以参考 MySQL 的 AUTOINCREMENT Handling in InnoDB 一文

死锁

概念:死锁是指两个或两个以上的事务执行过程中,因争夺资源而造成的一种互相等待的现象。

  1. 解决死锁第一种方法:超时,然后对事务回滚

缺点:若超时的事务所占权重比较大,如事务更新了很多行,占用了较多的undo log,这时采用FIFO方式就不合适了,因为回滚这个事务的时间相对另一个事务所占用的时间可能会多很多。

  1. wait-for graph等待图方式进行死锁检测

InnoDB采用的方式。

wait-for graph要求数据库保存两种信息,通过下面两个链表构造出一张图,如果这个图中存在回路,就代表存在死锁,因此资源间发生相互等待。

  • 锁的信息链表
  • 事务等待链表

如下图示例,事务等待链表有4个事务,而右边锁信息链表中,row1中事务t1要等待事务t2资源,所以在下wait-for graph图中就有一条t1指向t2的箭头;而row2中tt2、t3需要等待t1中占用row2资源,故t2、t3各有个箭头指向t1(t1、t4两个S锁兼容)。依次最后得到下面的图。

可以发现(t1, t2)存在回路,因此存在死锁。

所以wait-for graph是一种主动的死锁检查机制,若存在死锁,选择回滚undo量最小的事务。(wait-for graph采用图的深度优先算法)

参考:

《MySQL技术内幕》

https://mp.weixin.qq.com/s/PPfXH9a3jlNyxXpwB_DZDg

https://zhuanlan.zhihu.com/p/29150809

深入理解MySQL系列之锁的更多相关文章

  1. Mysql加锁过程详解(7)-初步理解MySQL的gap锁

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  2. 深入理解MySQL系列之redo log、undo log和binlog

    事务的实现 redo log保证事务的持久性,undo log用来帮助事务回滚及MVCC的功能. InnoDB存储引擎体系结构 redo log Write Ahead Log策略 事务提交时,先写重 ...

  3. 深入理解MySQL系列之索引

    索引 查找一条数据的过程 先看下InnoDB的逻辑存储结构: 表空间:可以看做是InnoDB存储引擎逻辑结构的最高层,所有的数据都存放在表空间中.默认有个共享表空间ibdata1.如果启用innodb ...

  4. 深入理解 MySQL ——锁、事务与并发控制

    本文首发于vivo互联网技术微信公众号 mp.weixin.qq.com/s/JFSDqI5ya… 作者:张硕 本文对 MySQL 数据库中有关锁.事务及并发控制的知识及其原理做了系统化的介绍和总结, ...

  5. [转帖]2019-03-26 发布 深入理解 MySQL ——锁、事务与并发控制

    深入理解 MySQL ——锁.事务与并发控制 https://segmentfault.com/a/1190000018658828 太长了 没看完.. 数据库 并发  mysql 639 次阅读   ...

  6. [转帖]深入理解 MySQL—锁、事务与并发控制

    深入理解 MySQL—锁.事务与并发控制 http://www.itpub.net/2019/04/28/1723/ 跟oracle也类似 其实所有的数据库都有相同的机制.. 学习了机制才能够更好的工 ...

  7. 深入理解mysql之BDB系列(1)---BDB相关基础知识

        深入理解mysql之BDB系列(1) ---BDB相关基础知识 作者:杨万富   一:BDB体系结构 1.1.BDB体系结构 BDB总体的体系结构如图1.1所看到的,包括五个子系统(见图1.1 ...

  8. MySQL强人“锁”难《死磕MySQL系列 三》

    系列文章 一.原来一条select语句在MySQL是这样执行的<死磕MySQL系列 一> 二.一生挚友redo log.binlog<死磕MySQL系列 二> 前言 最近数据库 ...

  9. S 锁与 X 锁的爱恨情仇《死磕MySQL系列 四》

    系列文章 一.原来一条select语句在MySQL是这样执行的<死磕MySQL系列 一> 二.一生挚友redo log.binlog<死磕MySQL系列 二> 三.MySQL强 ...

随机推荐

  1. 2019年第十届蓝桥杯【C++省赛B组】D、E、G、H、I题解

    这场有几道题目思路,在之前比赛中遇到过 D. 数的分解 #枚举 题意 将\(2019\)分解成\(3\)个各不相同的正整数之和,并且每个正整数都不包含数字\(2\)和\(4\),一共有多少种分解方法? ...

  2. dubbo起停之服务消费

    ReferenceAnnotationBeanPostProcessor继承了AnnotationInjectedBeanPostProcessors其实现了InstantiationAwareBea ...

  3. 利用Postman和Chrome的开发者功能探究项目

    利用Postman和Chrome的开发者功能探究项目 controller层研究 前两天忙着写开题报告,没有来得及做项目,今天继续研究一下这个项目. 上次研究到后端的DAO层,研究了一下后端和数据库交 ...

  4. BYTE WORD DWORD

    在Visual C++ 6.0中,BYTE与WORD,DWORD本质上都是一种无符号整型,它们在WINDEF.H中被定义,定义如下:typedef unsigned char       BYTE;t ...

  5. 基于 MongoDB 动态字段设计的探索 (二) 聚合操作

    业务需求及设计见前文:基于 MongoDB 动态字段设计的探索 根据专业计算各科平均分 (总分.最高分.最低分) public Object avg(String major){ Aggregatio ...

  6. 《Machine Learning in Action》—— 浅谈线性回归的那些事

    <Machine Learning in Action>-- 浅谈线性回归的那些事 手撕机器学习算法系列文章已经肝了不少,自我感觉质量都挺不错的.目前已经更新了支持向量机SVM.决策树.K ...

  7. [Windows] 在 Microsoft Docs 网站中挖掘 MVVM 的各种学习资源

    最近写了一些 MVVM 框架的文章,翻了一些 Microsoft Docs 的文档,顺便就对 MVVM 本身来了兴致,想看看更多当年相关的文档.在 MVVM 出现后十多年,我在不同的场合见到过多种 M ...

  8. 题解-CF755G PolandBall and Many Other Balls

    题面 CF755G PolandBall and Many Other Balls 给定 \(n\) 和 \(m\).有一排 \(n\) 个球,求对于每个 \(1\le k\le m\),选出 \(k ...

  9. Mysql LIMIT的用法

    使用范围 MySQL语句中的limit字句可以帮助我们在使用执行查询的时候,返回数据库中间的数据或者是只提取前几段数据 使用语法 SELECT * FROM table LIMIT [offset,] ...

  10. 使用纯js 不导包实现 table 导出 Excel

    1.将js粘贴到项目 2.设置table标签 id3.定义按钮,调用方法即可 1 <!DOCTYPE html> 2 <html lang="zh_CN"> ...