MySQL中InnoDB存储引擎的锁的基本使用教程


Posted in MySQL onMay 26, 2021

MyISAM和MEMORY采用表级锁(table-level locking)

BDB采用页面锁(page-leve locking)或表级锁,默认为页面锁

InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁

各种锁特点

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

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

页面锁:开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般

InnoDB存储引擎的锁

InnoDB存储引擎实现了如下两种锁

1、共享锁(S Lock),允许事务读一行数据

2、排他锁(X Lock),允许事务更新或者删除一行数据

共享锁和排他锁的兼容如下图所示
MySQL中InnoDB存储引擎的锁的基本使用教程

 

一致性的非锁定读

一致性的非锁定行读(consistent nonlocking read)是指InnoDB存储引擎通过行多版本控制(multi versioning)的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行DELETE、UPDATE操作,这是读取操作不会因此而会等待行上锁的释放,相反,InnoDB会去读取行的一个快照数据。

之所以称其为非锁定读,因为不需要等待访问的行上X锁的释放。快照数据是指改行之前版本的数据,该实现是通过undo段来实现的。但是在不同事务隔离级别下,读取的方式不同,并不是每个事务隔离级别下读取的都是一致性读。

例如:

对于read committed的事务隔离级别,他总是读取行的最新版本,如果行被锁定了,则读取该行版本的最新一个快照。

对于repeatable read(innoDB存储引擎的默认隔离级别),总是读取事务开始时的行数据。

 非锁定读的机制大大提高了数据读取的并发性,在Innodb存储引擎默认设置下,这是默认的读取方式,但是在某些情况下,可以对读进行加锁,比如:

1、显式对读进行加锁,如使用 select --- for update ;select --- lock in share mode

2、在外键的插入和更新上,因为在外键的插入和更新上,对于数据的隔离性要求较高,在插入前需要扫描父表中的记录是否存在,所以,在外键的插入删除上,InnoDB会使用加S锁的方式来实现。

InnoDB锁的算法

1、Record Lock:单个行记录上的锁

2、Gap Lock:间隙锁,锁定一个范围,但不包含记录本身

3、Next-key Lock:Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身

Record Lock总是会去锁住索引记录,如果InnoDB存储引擎表建立的时候没有设置任何一个索引,这时InnodB存储引擎会使用隐式的主键来进行锁定,在Repeatable Read隔离级别下,Next-key Lock 算法是默认的行记录锁定算法。

锁带来的问题

1、丢失更新

如何避免丢失更新:让事务变成串行操作,而不是并发的操作,即对每个事务开始---对读取记录加排他锁。

2、脏读

脏读即一个事务可以读到另一个事务中未提交的数据,这违反了数据库的隔离性。

脏读发生的条件是需要事务的隔离级别为Read uncommitted。

3、不可重复读

不可重复读与脏读的区别是:脏读是读到未提交的数据,而不可重复读读到的是已经提交的数据。

一般来说,不可重复读是可以接受的,在InnoDB存储引擎中,通过使用Next-Key Lock算法来避免不可重复读的问题。

值得注意的是,默认情况下InnoDB存储引擎不会回滚超时引发的错误异常。

死锁的相关问题

1、死锁发生的条件

互斥条件:一个资源每次只能被一个进程使用;请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺;循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

2、死锁检测(根据网上的经验)

Innodb检测死锁有两种情况,一种是满足循环等待条件,还有另一种策略:锁结构超过mysql配置中设置的最大数量或锁的遍历深度超过设置的最大深度时,innodb也会判断为死锁(这是提高性能方面的考虑,避免事务一次占用太多的资源)。

因循环等待条件而产生的死锁只有可能是四种形式:两张表两行记录交叉申请互斥锁、同一张表则存在主键索引锁冲突、主键索引锁与非聚簇索引锁冲突、锁升级导致的锁等待队列阻塞。

3、死锁避免(根据网上的经验)

1.如果使用insert…select语句备份表格且数据量较大,在单独的时间点操作,避免与其他sql语句争夺资源,或使用select into outfile加上load data infile代替 insert…select,这样不仅快,而且不会要求锁定
2. 一个锁定记录集的事务,其操作结果集应尽量简短,以免一次占用太多资源,与其他事务处理的记录冲突。
3.更新或者删除表格数据,sql语句的where条件都是主键或都是索引,避免两种情况交叉,造成死锁。对于where子句较复杂的情况,将其单独通过sql得到后,再在更新语句中使用。
4. sql语句的嵌套表格不要太多,能拆分就拆分,避免占有资源同时等待资源,导致与其他事务冲突。
5. 对定点运行脚本的情况,避免在同一时间点运行多个对同一表进行读写的脚本,特别注意加锁且操作数据量比较大的语句。
6.应用程序中增加对死锁的判断,如果事务意外结束,重新运行该事务,减少对功能的影响。

4、死锁解决

1)先执行show processlist找到死锁线程号.然后Kill pid

2)Show innodb status检查引擎状态 ,可以看到哪些语句产生死锁

3)查看information_schema架构下的innodb_locks、innodb_trx、innodb_lock_waits等表

 
PS:Mysql死锁

既然谈到死锁,那附带地就专门说一下。
何为死锁?
 
死锁是对资源的分配和使用不当而造成的。是两个进程争夺某一资源而出现相互等待的现象。具体的来讲,出现死锁需要满足四个必要条件:
(1)互斥条件:每一个资源都只能被一个进程使用
(2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
(3)不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
很显然,出现死锁需要两个或者两个以上的进程,换句话说,死锁发生在并发的程序中。在Mysql中,由于目前只有InnoDB引擎使用事务(InnoDB支持锁),便有了InnoDB和死锁的旷世基情。
死锁的检测
 
1、通过使用Show innodb status检查引擎状态 ,可以看到哪些语句产生deadlock
2、MySQL提供了一个information_schema,通过查看innodb_locks、innodb_trx、innodb_lock_waits这几个表检测死锁。
因循环等待条件而产生的死锁只有可能是四种形式:两张表两行记录交叉申请互斥锁、同一张表则存在主键索引锁冲突、主键索引锁与非聚簇索引锁冲突、锁升级导致的锁等待队列阻塞。

死锁避免

1.如果使用insert…select语句备份表格且数据量较大,在单独的时间点操作,避免与其他sql语句争夺资源,或使用select into outfile加上load data infile代替 insert…select,这样不仅快,而且不会要求锁定
2. 一个锁定记录集的事务,其操作结果集应尽量简短,以免一次占用太多资源,与其他事务处理的记录冲突。
3.更新或者删除表格数据,sql语句的where条件都是主键或都是索引,避免两种情况交叉,造成死锁。对于where子句较复杂的情况,将其单独通过sql得到后,再在更新语句中使用。
4. sql语句的嵌套表格不要太多,能拆分就拆分,避免占有资源同时等待资源,导致与其他事务冲突。
5. 对定点运行脚本的情况,避免在同一时间点运行多个对同一表进行读写的脚本,特别注意加锁且操作数据量比较大的语句。
6.应用程序中增加对死锁的判断,如果事务意外结束,重新运行该事务,减少对功能的影响。

MySQL 相关文章推荐
MySQL 隔离数据列和前缀索引的使用总结
May 14 MySQL
Mysql官方性能测试工具mysqlslap的使用简介
May 21 MySQL
浅谈MySQL user权限表
Jun 18 MySQL
MySQL子查询中order by不生效问题的解决方法
Aug 02 MySQL
MySQL的全局锁和表级锁的具体使用
Aug 23 MySQL
面试被问select......for update会锁表还是锁行
Nov 11 MySQL
SQL注入篇学习之盲注/宽字节注入
Mar 03 MySQL
MySQL创建表操作命令分享
Mar 25 MySQL
MySQL外键约束(Foreign Key)案例详解
Jun 28 MySQL
MySQL实现字段分割一行转多行的示例代码
Jul 07 MySQL
Mysql中mvcc各场景理解应用
Aug 05 MySQL
MySQL远程无法连接的一些常见原因总结
Sep 23 MySQL
MySql存储过程之逻辑判断和条件控制
MYSQL主从数据库同步备份配置的方法
May 26 #MySQL
MYSQL数据库使用UTF-8中文编码乱码的解决办法
May 26 #MySQL
Mysql效率优化定位较低sql的两种方式
May 26 #MySQL
Mysql中 unique列插入重复值该怎么解决呢
May 26 #MySQL
MySQL查看表和清空表的常用命令总结
May 26 #MySQL
MySQL中distinct与group by之间的性能进行比较
You might like
php smarty模版引擎中的缓存应用
2009/12/11 PHP
PHP生成唯一的促销/优惠/折扣码(附源码)
2012/12/28 PHP
php实现的常见排序算法汇总
2014/09/08 PHP
PHP获取昨天、今天及明天日期的方法
2016/02/03 PHP
PHP框架Laravel插件Pagination实现自定义分页
2020/04/22 PHP
Laravel框架基于ajax实现二级联动功能示例
2019/01/17 PHP
Laravel框架实现多数据库连接操作详解
2019/07/12 PHP
js 对象是否存在判断
2009/07/15 Javascript
javascript中的void运算符语法及使用介绍
2013/03/10 Javascript
借助script进行Http跨域请求:JSONP实现原理及代码
2013/03/19 Javascript
用JQuery 判断某个属性是否存在hasAttr的解决方法
2013/04/26 Javascript
一个JS的日期格式化算法示例
2013/07/31 Javascript
解决json日期格式问题的3种方法
2014/02/02 Javascript
jQuery中复合属性选择器用法实例
2014/12/31 Javascript
Jquery基础之事件操作详解
2016/06/14 Javascript
针对BootStrap中tabs控件的美化和完善(推荐)
2016/07/06 Javascript
AngularJS中实现动画效果的方法
2016/07/28 Javascript
JQuery查找子元素find()和遍历集合each的方法总结
2017/03/07 Javascript
jQuery+Ajax实现用户名重名实时检测
2017/06/01 jQuery
详解jQuery中的getAll()和cleanData()
2019/04/15 jQuery
Js和VUE实现跑马灯效果
2020/05/25 Javascript
vue项目或网页上实现文字转换成语音播放功能
2020/06/09 Javascript
[01:01:51]EG vs VG Supermajor小组赛B组 BO3 第二场 6.2
2018/06/03 DOTA
Django中更改默认数据库为mysql的方法示例
2018/12/05 Python
Python图像处理实现两幅图像合成一幅图像的方法【测试可用】
2019/01/04 Python
解决Keras 自定义层时遇到版本的问题
2020/06/16 Python
基于HTML5的WebGL实现json和echarts图表展现在同一个界面
2017/10/26 HTML / CSS
感恩母亲节活动方案
2014/03/04 职场文书
党员教师四风问题对照检查材料
2014/09/26 职场文书
分居协议书范本(律师见证版)
2014/11/26 职场文书
社区活动总结范文
2015/05/07 职场文书
2015社区个人工作总结范文
2015/05/13 职场文书
Python生成九宫格图片的示例代码
2021/04/14 Python
golang elasticsearch Client的使用详解
2021/05/05 Golang
Java 泛型详解(超详细的java泛型方法解析)
2021/07/02 Java/Android
Redis sentinel哨兵集群的实现步骤
2022/07/15 Redis