在互联网大并发应用大行其道的今天,应用的开发总是离不开锁,在分布式应用中,最常见的莫过于基于数据库的行级锁了,由于互联网公司中比较主流的数据库还是mysql,所以这一话题绕不开的就是mysql了,但是由于mysql中innoDb引擎特殊的机制,经常一不小心就会发生死锁,本次咱们就来聊一聊基于mysql innodb 实现的行级锁,以及为什么会产生死锁,和如何避免死锁

首先,使用mysql实现行级锁的两大前提就是,innodb引擎并且开启事务。由于MySQL/InnoDB的加锁分析,一直是一个比较困难的话题。本次咱们暂时只讨论在日常应用中 select .... from table where ..... for update 语句并且在 Repeatable Read 事务隔离级别下

在此之前先明确几个概念:

1.Index Key:

用于确定SQL查询在索引中的连续范围(起始范围+结束范围)的查询条件,被称之为Index Key。

2.Index Filter:

在完成Index Key的提取之后,我们根据where条件固定了索引的查询范围,但是此范围中的项,并不都是满足查询条件的项。根据其他条件排除此范围中不满足的项

3.Table Filter:

所有不属于索引列的查询条件,均归为Table Filter之中。

一个sql的筛选过程就是先Index Key 到 Index Filter 再到 Table Filter。

其实死锁最大的难点可能就是很多人不知道一条for update到底是怎么加锁的,而在innodb引擎中行级锁分为以下三种锁

1.Record Lock

单个行记录上的锁

2.Gap Lock

间隙锁,锁定一个范围,不包括记录本身

3.Next-Key Lock

锁定一个范围和记录本身

我们分以下举例说明:

select * from table where id = 1 for update;

id 是主键的时候,本条sql在Index Key阶段可以确定唯一一条数据,所以会在聚簇索引上加Record Lock

id 是普通索引的时候,本条sql在Index Key阶段筛选出的数据不具有唯一性,所以Innodb为了防止幻度,会加Gap Lock+Next-Key Lock(Repeatable Read 事务隔离级别下,在Table Filter阶段对相应的聚簇索引上加Record Lock

id 不是索引的时候,本条sql在Table Filter阶段进行全表扫描,会在所有的聚簇索引上加锁,相当于全表锁,这是由于MySQL的实现决定的。如果一个条件无法通过索引快速过滤,那么innodb引擎层面就会将所有记录对应的聚簇索引加锁后返回,然后由MySQL Server层进行过滤,在高版本的mysql中会将不符合的记录再解锁

select * from table where id = 1 and time = '2019-06-18' for update;

id 是主键,time不是索引的时候,本条sql在Index Key阶段可以确定唯一一条数据,Index Filter,Table Filter 都只有一条数据,所以会在聚簇索引上加Record Lock.

id 是普通索引,time不是索引的时候,本条sql在Index Key阶段筛选出的数据不具有唯一性,所以Innodb为了防止幻度,会加id和小于1的索引之间加Next-Key Lock锁,在大于id和下一个索引之间加和Gap Lock锁(Repeatable Read 事务隔离级别下),Table Filter阶段会扫描出id = 1 范围下所有的聚簇索引加锁

id 不是索引,time不是索引的时候,本条sql在Table Filter阶段进行全表扫描,会在所有的聚簇索引上加锁,相当于全表锁

id 和time都是普通索引的时候,会再id索引和time索引上分别加Next-Key Lock和Gap Lock,在Table Filter阶段对相应的聚簇索引上加Record Lock

由上两个例子得出,我们的for update 并不时都锁一条记录,也并不是只有一个锁,这两个例子基本上已经包含了for update中常见的锁,在此基础上我们可以根据MySQL的加锁规则,写出不会发生死锁的SQL,比如,只用聚簇索引做where条件,也可以根据MySQL的加锁规则,定位出线上产生死锁的原因。

你真的会用mysql行级锁吗?mysql 行级锁全解析的更多相关文章

  1. MySQL十种锁,一篇文章带你全解析

    MySQL有两个核心的知识点,索引和锁.前几篇文章已经详细讲解了MySQL索引实现机制,今天再一起学习一下MySQL的锁. 1 为什么要加锁? 当多个事务并发操作同一批数据的时候,如果不加锁,就无法保 ...

  2. Mysql的视图、存储过程、函数、索引全解析

    视图是查询命令结果构成的一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集合,并可以当作表来查询使用. 1创建视图 --格式:C ...

  3. MySQL学习笔记(五):MySQL表级锁和行级锁

    一:概述 相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制.比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking ...

  4. mysql锁——innodb的行级锁

    [前言]数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则.MySQL数据库由于其自身架构的特点,存在多种数据存储引擎,每种存储引擎所针对的应 ...

  5. 极客时间 Mysql实战45讲 07讲行锁功过:怎么减少行锁对性能的影响笔记 极客时间

    极客时间 Mysql实战45讲 07讲行锁功过:怎么减少行锁对性能的影响笔记 极客时间极客时间 Mysql实战45讲 07讲行锁功过:怎么减少行锁对性能的影响笔记 极客时间 笔记体会: 方案一,事务相 ...

  6. mysql锁机制之行锁(四)

    前言 顾名思义,行锁就是一锁锁一行或者多行记录,mysql的行锁是基于索引加载的,所以行锁是要加在索引响应的行上,即命中索引,如下图所示: InnoDB 支持多粒度锁(multiple granula ...

  7. 【问答分享第一弹】MySQL锁总结:MySQL行锁、表锁、排他锁、共享锁的特点

    大家好,我是小于哥哈.前几天能分享了第一期面试题,MySQL 中有哪几种锁 和 这些锁各有哪些特点 ,这道面试题是经常会被问到的一个面试题,大家反馈的都挺不错的.今天特此来总结一下. 首发于公众号[终 ...

  8. MySQL 笔记整理(7) --行锁功能:怎么减少行锁对性能的影响?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> 7) --行锁功能:怎么减少行锁对性能的影响? MySQL的行锁是在引擎层由各个引擎自己实现的.因此,并不是所有的引擎都支持行锁,如 ...

  9. MySQL中锁详解(行锁、表锁、页锁、悲观锁、乐观锁等)

    悲观锁: 顾名思义,很悲观,就是每次拿数据的时候都认为别的线程会修改数据,所以在每次拿的时候都会给数据上锁.上锁之后,当别的线程想要拿数据时,就会阻塞,直到给数据上锁的线程将事务提交或者回滚.传统的关 ...

随机推荐

  1. 计算机的组成 —— PCI(PCIE)、PCB

    1. PCI PCI 是 Peripheral Component Interconnect(外设部件互连标准)的缩写,它是目前个人电脑中使用最为广泛的接口,几乎所有的主板产品上都带有这种插槽. PC ...

  2. C# 比较不错的通用验证码

    1 using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging ...

  3. Windows10 【系统周期表】【系统下载表】【大型软件表】

    系统周期表 商用名称 商用英文名 代号 版本 系统版本 上市日期 服务周期 备注 Windows 10 无 Threshold 1 1507 10.0.10240.17443 2015.07.29 2 ...

  4. MongoDB对文档的操作

    插入文档 db.COLLECTION_NAME.insert({doc1},{doc2},...) e.g.:db.collection.insert({name:'123',age:12},{nam ...

  5. MinGW 编译 libsndfile-1.0.25(只要有 MSYS,./configure make make install 就行了)

    最近做的一个项目需要读写 wav 文件.在网上找到 libsndfile 刚好满足我的需要.但是编译的时候遇到了点小麻烦,这里记录一下编译的过程,免得下次再编译时忘记了. 因为是在编译完成若干天后写的 ...

  6. Qt在各平台上的搭建qt-everywhere(Qt for windows7-64bit, Ubuntu 12.04-32bit, 嵌入式x86平台, 嵌入式arm平台)

    下载地址:http://download.qt.io/ 当进入解压好的源码包后,使用./configure –help命令,可以获得相应帮助,前面是*号的表示默认参数. +号表示该功能要求被评估,评估 ...

  7. OpenSSL的命令行用法,以及参数大全

    c:\openssl\bin>opensslOpenSSL> versionOpenSSL 1.0.2j 26 Sep 2016OpenSSL> https://wiki.opens ...

  8. QT父子窗口事件传递与事件过滤器(讲了一些原理,比较清楚)

    处理监控系统的时候遇到问题,在MainWidget中创建多个子Widget的时候,原意是想鼠标点击先让MainWidget截获处理后再分派给子Widget去处理,但调试后发现如果子Widget重新实现 ...

  9. Qt之QSS(QTreeView)

    check 是选中 前面的指示器的状态 select 是选中 项目 item 的状态. http://blog.csdn.net/u011012932/article/details/52606662

  10. 怎么看待php 面向对象思想

    面向对象的程序设计思路是现代程序设计由面向过程演变面向对象的必然趋势,所以面向对象的而设计思路必然有它不同的时代意义,必然有着不同面向过程的不同历史使命,而php 5以后成功添加面向对象的设计思路其实 ...