按锁思想分类
  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. [GIT]获取git最新的tag

    背景 公司前端项目在Jenkins中打包,每次打包需要将新tag回推到仓库中.但是打包失败后如果不删除tag的话下次打包就会失败,需要手动删除,所以在Jenkinsfile中就需要在打包失败时自动删除 ...

  2. C++基础知识篇:C++ 存储类

    存储类定义 C++ 程序中变量/函数的范围(可见性)和生命周期.这些说明符放置在它们所修饰的类型之前.下面列出 C++ 程序中可用的存储类: auto register static extern m ...

  3. rocketmq的吞吐量为什么小于kafka

    转载: https://www.jianshu.com/p/c474ca9f9430

  4. CentOS升级参考

    CentOS生产系统升级策略: 1)升级前评估 a)确认kernel或包bug. b)用评估工具 c) 测试验证 2)确认升级内容 a)单独升级kernel b)单独升级包 c)都升级 4)确认升级方 ...

  5. Java 在Excel中添加分离型饼图、环形图

    一.概述 Excel中可支持多种不同类型的图表,本文介绍如何绘制分离型饼图和环形图.其中,分离型饼图的绘制可分为整体分离型(即设置饼图分离程度)和局部分离(即设置点爆炸型值)两种情况.下面将以Java ...

  6. C#(一)基础篇—类型与变量

    于今日起学习巩固C#基础 2020-12-01 本随笔用于个人回忆理解,记录当天学习过程,内容多从书中整理与自我学习了解,如有问题麻烦指正 以后有时间会单独分版块叙述 不管什么语言,都从一个Hello ...

  7. windows下使用pyinstaller将多个目录的Python文件打包成exe可执行文件

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.引言 需要将一个工程涉及两个目录的模块文件打包成exe,打包环境如 ...

  8. Oracle命令管理账户和权限

    方式一.登陆数据库SQL PLUS: 步骤:Oracle - OraDb10g_home1 =>应用程序开发=>SQL PLUS 用户名:system 密码:tiger/admin 退出数 ...

  9. LeetCode初级算法之数组:1 两数之和

    两数之和 题目地址:https://leetcode-cn.com/problems/two-sum/ 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个整 ...

  10. Kruskal重构树——[NOI2018] 归程

    题目链接: UOJ LOJ 感觉 Kruskal 重构树比较简单,就不单独开学习笔记了. Statement 给定一个 \(n\) 点 \(m\) 边的无向连通图,用 \(l,a\) 描述一条边的长度 ...