1. 锁的基础与行锁的特点

1.1 概念

  • 在开发多用户、数据库驱动的应用时,相当大的一个难点就是解决并发性的问题,目前比较常用的解决方案就是锁机制。
  • 锁机制也是数据库系统区别于文件系统的一个关键特性。
  • InnoDB 存储引擎和 MyISAM 存储引擎使用的是完全不同的策略。

1.2 锁的类型

  1. 相比其他数据库而言,MySQL 的锁机制比较简单,而且不同的存储引擎支持不同的锁机制。
  2. MyISAM 和 Memory 存储引擎使用的是表级锁,BDB 引擎使用的是页级锁,也支持表级锁。由于 BDB
    引擎基本已经成为历史,因此就不再介绍了。
  3. InnoDB 存储引擎既支持行级锁,也支持表级锁,默认情况下使用行级锁。
  • 表级锁,它直接锁住的是一个表,开销小,加锁快,不会出现死锁的情况,锁定粒度大,发生锁冲突的概率更高,并发度最低。
  • 行级锁,它直接锁住的是一条记录,开销大,加锁慢,发生锁冲突的概率较低,并发度很高。行级锁更适合大量按照索引条件并发更新少量不同的数据,同时还有并发查询的应用,比如一些在线事务处理系统,即OLTP(事务处理)。
  • 页级锁,它是锁住的一个页面,在 InnoDB 中一个页面为16KB,它的开销介于表级锁和行级锁中间,也可能会出现死锁,锁定粒度也介于表级锁和行级锁中间,并发度也介于表级锁和行级锁中间。仅仅从锁的角度来说,表级锁更加适合于以查询为主的应用,只有少量按照索引条件更新数据的应用,比如大多数的 web 应用。

1.3 innodb锁

InnoDB 与 MyISAM 的相当大的两点不同在于: (1) 支持事务 (2) 采用行级锁

  • 行级锁本身与表级锁的实现差别就很大,而事务的引入也带来了很多新问题,尤其是事务的隔离性,与锁机制息息相关。
  • 数据库实现事务隔离的方式,基本可以分为两种:
    (1) 在操纵数据之前,先对其加锁,防止其他事务对数据进行修改。这就需要各个事务串行操作才可以实现。
    (2) 不加任何锁,通过生成一系列特定请求时间点的一致性数据快照,并通过这个快照来提供一致性读取。
    上面的第二种方式就是数据多版本并发控制,也就是多版本数据库,一般简称为 MVCC 或者 MCC,它是 Multi Version Concurrency Control 的简写。
  • 数据库的事务隔离越严格,并发的副作用就越小,当然付出的代价也就越大,因为事务隔离机制实质上是使得事务在一定程度上”串行化”,这与并行是矛盾的。

1.4 innodb锁类型

  1. InnoDB 实现了下面两种类型的锁:
  • 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
  • 排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务获得相同数据集的共享读锁和排他写锁。
  1. 这里有个锁兼容和冲突的概念,如果在加一个锁的时候,另一个锁可以加上去,那么就是锁兼容。如果加上一个锁之后,拒绝其他的锁加上,那么就是锁冲突。
  1. 意向共享锁(IS锁):事务在请求S锁前,要先获得IS锁
  2. 意向排他锁(IX锁):事务在请求X锁前,要先获得IX锁
  1. 各种锁的兼容冲突情况如下:
  • X 和所有锁都冲突
  • IX 兼容 IX 和 IS
  • S 兼容 S 和 IS
  • IS 兼容 IS、IX 和 S
  1. 如果一个事务请求的锁模式与当前的锁兼容,InnoDB 就将请求的锁授予该事务,如果两者是冲突的,那么该事务就要等待锁释放。
  2. 对于 update、delete、insert 语句,InnoDB 会自动给设计到的数据集加排他锁即 X。
  3. 对于 select 语句,InnoDB 不会加任何锁。
  4. 可以使用如下语句来显式的给数据集加锁:
  • 共享锁(S):select * from t1 where … lock in share mode;
  • 排他锁(X):select * from t1 where … for update;
  1. 我们可以用 select …in share mode 来获得共享锁,主要用在数据依存关系时来确认某行记录是否存在,并确认没有人对这个记录进行 update 或者 delete 操 作。
  2. 我们可以使用 select… for update 来获得排他锁,它会拒绝其他事务在其上加其他锁。

1.5 锁对于语句的加锁

  1. 排它锁
  • 当前事务给一行数据加锁,那么其他事务将不能在对数据做任何操作,即:不能读不能写,也不能与其他锁一起使用
  • 语法格式如下:
--给`user`表id为1的数据加排它锁
start transaction--开启事务
select * from `user` where id=1 for update;--给id为1的数据加排它锁
commit;--提交事务
rollback;--回滚事务
  1. 共享锁
  • 当前事务给一行数据加共享锁,那么其他事务可以加共享锁,但不能加排它锁。即:能读不能写,可以与共享锁一起使用,但不能与排它锁一起使用;
  • 语法格式如下:
--给`user`表id为1的数据加共享锁
start transaction--开启事务
select * from `user` where id=1 lock in share mode;--给id为1的数据加共享锁
commit;--提交事务
rollback;--回滚事务

2. 死锁的产生于处理

  1. 死锁产生的原因

死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB。

  • 死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。
  • 那么对应的解决死锁问题的关键就是:让不同的session加锁有次序
  1. 死锁的现象
    事务1事务2分别对id为1与id为2的数据进行排它锁加锁,随后进行交叉的数据修改。

  2. 尽可能的避免事务死锁

  • 以固定的顺序访问表和行。比如对第2节两个job批量更新的情形,简单方法是对id列表先排序,后执行,这样就避免了交叉等待锁的情形;又比如对于3.1节的情形,将两个事务的sql顺序调整为一致,也能避免死锁。
  • 大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。
  • 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。
  • 降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁。
  • 为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大。

3. 乐观锁与悲观锁的解释

  • 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
  • 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
  1. MVCC-多版本并发控制实现乐观锁

多版本并发控制 (Multiversion concurrency control, MCC 或 MVCC),是数据库管理系统常用的一种并发控制,也用于程序设计语言实现事务内存。

  1. 总的来说,MVCC 的出现就是数据库不满用悲观锁去解决读 - 写冲突问题,因性能不高而提出的解决方案。
  2. 当前读和快照读
  • 当前读
    像 select lock in share mode (共享锁), select for update ; update, insert ,delete (排他锁)
    这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。
  • 快照读
    像不加锁的 select 操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是未提交读和串行化级别,因为未提交读总是读取最新的数据行,而不是符合当前事务版本的数据行。而串行化则会对所有读取的行都加锁
  • 优缺点
    MVCC 使大多数读操作都可以不用加锁,这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行。不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。

4. 间隙锁与行锁升级为表锁

  1. 间隙锁
  • 当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(NEXT-KEY)锁。
  • 危害:
    因为Query执行过程中通过范围查找的话,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定值范围内的任何数据,在某些场景下这可能会针对性造成很大的危害。
  1. 行锁升级为表锁

众所周知,MySQL 的 InnoDB 存储引擎支持事务,支持行级锁(innodb的行锁是通过给索引项加锁实现的)。得益于这些特性,数据库支持高并发。如果 InnoDB 更新数据使用的不是行锁,而是表锁呢?是的,InnoDB 其实很容易就升级为表锁,届时并发性将大打折扣了。

  • 常用的索引有三类:主键、唯一索引、普通索引。主键 不由分说,自带最高效的索引属性;唯一索引指的是该属性值重复率为0,一般可作为业务主键,例如学号;普通索引 与前者不同的是,属性值的重复率大于0,不能作为唯一指定条件,例如学生姓名。
  1. 在不使用索引的情况下进行加锁

    运行结果如下:

在不给age字段加索引的情况下进行排它锁的加锁操作,可以看到尽管加锁的数据是不同的,但是事务2在加锁时出现了所等待现象。说明此时事务1从行锁升级为表锁,导致事务2在给age=10的数据加锁时出现了所等待现象。

  1. 在使用普通索引的情况进行加锁
alter table user add index idx_age(age); --给age字段加个索引


运行结果:

在加了索引之后,再一次进行以上操作,可以看到,user表不在进行表锁,那是因为行锁是建立在索引字段的基础上,如果行锁定的列不是索引列则会升级为表锁

  1. 范围性查询测试

    运行结果:

当要进行加锁的数据不确定时,也一样会是表锁。

总结:

  • 行锁是建立在索引的基础上。
  • 普通索引的数据重复率过高导致索引失效,行锁升级为表所

mysql锁机制(共享锁(S)、排他锁(X)、意向共享锁(IS)、意向排他锁(IX)的关系,死锁,乐观锁,悲观锁...)相关推荐

  1. mysql乐观和悲观锁实现_mysql实现乐观锁和悲观锁该怎么编写?

    乐观锁和悲观锁相信大家都是知道的,这是java中的基础知识,今天我们就来看看它们两者该如何使用代码实现吧. 乐观锁实现 1).表设计 表task,分别有三个字段id,value.version 2). ...

  2. mysql 悲观锁 共享锁_MySQL 乐观锁 悲观锁 共享锁 排他锁

    乐观锁 乐观锁是逻辑概念上的锁,不是数据库自带的,需要我们自己去实现.乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁 ...

  3. MySQL/InnoDB中,乐观锁、悲观锁、共享锁、排它锁、行锁、表锁、死锁概念的理解

    MySQL/InnoDB的加锁,一直是一个面试中常问的话题.例如,数据库如果有高并发请求,如何保证数据完整性?产生死锁问题如何排查并解决?我在工作过程中,也会经常用到,乐观锁,排它锁,等.于是今天就对 ...

  4. mysql 锁机制及实现原理_MySQL-深入浅出锁分类及实现原理

    个人公众号『码农札记』,欢迎关注,查看更多精彩文章. 背景 数据库是一个多用户并发使用的共享资源.当多个并发读写数据时,在数据库中就会产生多个事务同时读写同一数据的情况. 若对并发操作不加控制就可能会 ...

  5. MySQL/InnoDB中,乐观锁、悲观锁、共享锁、排它锁、行锁、表锁、死锁概念的理解...

    2019独角兽企业重金招聘Python工程师标准>>> MySQL/InnoDB的加锁,一直是一个面试中常问的话题.例如,数据库如果有高并发请求,如何保证数据完整性?产生死锁问题如何 ...

  6. mysql的乐观锁,悲观锁(共享锁,排斥锁)

    mysql的并发操作时而引起的数据的不一致性(数据冲突): 丢失更新:两个用户(或以上)对同一个数据对象操作引起的数据丢失. 解决方案:1.悲观锁,假设丢失更新一定存在:sql后面加上**for up ...

  7. mysql的锁机制(读锁,写锁,表锁,行锁,悲观锁,乐观锁,间隙锁)

    读锁和写锁 介绍 MyISAM表锁中的读锁和写锁 读锁(共享锁S): 对同一个数据,多个读操作可以同时进行,互不干扰.加锁的会话只能对此表进行读操作,其他会话也只能进行读操作.MyISAM的读默认是加 ...

  8. MySQL数据库读现象 数据库锁机制 Innodb存储引擎行级锁

    数据库读现象 数据库管理软件的"读现象"指的是当多个事务并发执行时,在读取数据方面可能碰到的问题,包括有脏读.不可重复读和幻读. 创建数据表 # 创建数据表 create tabl ...

  9. mysql innodb 并发 插入 慢_Innodb 锁机制——一次插入慢查询的排查

    慢查询日志中,发下有一条插入语句慢查询出现的概率比较高,一个简单插入需要消耗4-10s,很不寻常.附上插入语句,省略了一些字段 INSERT INTO `fc_pay_out_trade_log` ( ...

  10. Java中的锁机制 -- 乐观锁、悲观锁、自旋锁、可重入锁、读写锁、公平锁、非公平锁、共享锁、独占锁、重量级锁、轻量级锁、偏向锁、分段锁、互斥锁、同步锁、死锁、锁粗化、锁消除

    文章目录 1. Java中的锁机制 1.1 乐观锁 1.2 悲观锁 1.3 自旋锁 1.4 可重入锁(递归锁) 1.5 读写锁 1.6 公平锁 1.7 非公平锁 1.8 共享锁 1.9 独占锁 1.1 ...

最新文章

  1. Angular 下的 directive (part 2)
  2. c# LUA 互通,相关资料收集
  3. 图像处理技术(三)白平衡
  4. 闭门宅家后,才知道这15个“真相”
  5. python tkinter库函数详解_Python使用tkinter库进行GUI编程中常用事件处理方式汇总
  6. 漫步微积分二十六——Sigma符号和一些特殊和
  7. C++/C--Windows下获取键盘事件
  8. Rivian计划在乔治亚州新增一个工厂
  9. java soap api操作和发送soap消息
  10. java页面分页显示代码_通用分页jsp页面显示
  11. 字符编码(1)——Unicode,utf-8
  12. LeetCode Can I Win
  13. c# AD域 权限管理
  14. linux 版本号 笔记本_Linux版ThinkPad笔记本正式亮相(图)
  15. Gentoo 教程:基本系统安装
  16. 读《拆掉思维的墙》小记
  17. ARP协议详解(3)--arp欺骗
  18. 在CentOS7上源码安装MongoDB 3.2.7
  19. 什么样的人才是幸福的?
  20. FCPX:600种VHS Studio转场效果合集

热门文章

  1. vue 日历翻拍效果_vue实现简单的日历效果
  2. kali设置自动锁屏时间
  3. 安财《Python语言程序设计》程序设计题
  4. zabbix监控nginx,网易Java面试流程
  5. Farrago for Mac(好用的音频编辑软件)
  6. Threejs实现开门关门动画
  7. 开学优惠高颜值蓝牙耳机排行榜,2021最佳游戏伴侣,低延迟蓝牙耳机推荐
  8. Eliminate the sound of the iPad of Japanese(J) Version
  9. 我的世界1.6.2服务器修改器,我的世界1.6.2服务器指令大全 服务器指令
  10. 08年最火的qq个性签名