• 老刘是即将找工作的研究生,自学大数据开发,一路走来,感慨颇深,网上大数据的资料良莠不齐,于是想写一份详细的大数据开发指南。这份指南把大数据的【基础知识】【框架分析】【源码理解】都用自己的话描述出来,让伙伴自学从此不求人。
  • 您的点赞是我持续更新的动力,禁止白嫖,看了就要有收获,一起加油。

今天给大家分享的是大数据开发基础部分MySQL的锁,锁在MySQL知识点中属于比较重要的部分,大家一定要好好体会老刘的话,MySQL锁篇的大纲如下:

看完老刘这篇内容后,希望你们能够掌握以下内容:

  1. MySQL的锁分类
  2. 表级锁中表锁、元数据锁的原理
  3. 行锁的原理、记录锁和间隙锁的使用区别、死锁的原理和死锁场景

MySQL锁介绍

为什么有锁?

多个程序对MySQL表或记录进行访问,就会产生竞态条件,为了解决这个问题,就提出了锁。

MySQL中的锁如下图:

MySQL表级锁

表级锁是由MySQL SQL layer层实现,只要锁了一张表,只能对这张表操作。它有两种:一是表锁、二是元数据锁。

表锁

表锁有两种表现形式:一是表共享读锁(Table Read Lock)、二是表独占写锁(Table Write Lock)。

我们采用手动增加表锁,采用如下SQL语句:

  1. lock table 表名称 read(write),表名称2 read(write),其他;

删除表锁,采用如下SQL语句:

  1. unlock tables;

查看表锁情况:

  1. show open tables;

光说不练假把式,老刘用一个案例给各位伙伴好好讲讲表锁,大家跟着一起练。

表锁演示

  1. --新建表
    CREATE TABLE mylock (
    id int(11) NOT NULL AUTO_INCREMENT,
    NAME varchar(20) DEFAULT NULL,
    PRIMARY KEY (id)
    );
    INSERT INTO mylock (id,NAME) VALUES (1, 'a');
    INSERT INTO mylock (id,NAME) VALUES (2, 'b');
    INSERT INTO mylock (id,NAME) VALUES (3, 'c');
    INSERT INTO mylock (id,NAME) VALUES (4, 'd');

演示表读锁

1、我们先给表mylock加表读锁

  1. session1: lock table mylock read;

2、加完表读锁后,session1还是能对该表进行查询

  1. session1: select * from mylock;

3、只要锁了这张表,就只能先对这张表操作,不能访问别的表,直到这张表被释放。我用session1访问表tdep就不能进行访问,如图:

4、虽然对这张表加锁了,但我们别的session可以对它进行访问。

  1. session2select * from mylock;

5、但如果session2要对mylock表进行修改,那就不行了,表读锁不允许加写锁,只允许加读锁,这也叫表共享读。

  1. session2update mylock set name='x' where id=2;

6、这个时候session1释放,session2才能进行修改。

  1. session1unlock tables;
    session2Rows matched: 1 Changed: 1 Warnings: 0 -- 修改执行完成

表读锁的内容就演示完了,现在开始演示表写锁的内容。

1、先给mylock加写锁

  1. session1: lock table mylock write;

2、session1可以访问mylock表,但不能访问其他表。

3、session1也可以对该表进行修改,但是session2对该表进行读取和修改就不行。

4、当session1释放表写锁后,session2才能获取。

  1. session1unlock tables;

  1. session24 rows in set (41.65 sec)

通过这个例子,大家要明白读锁就是表共享读锁,自己可以用,其他人也可以访问;写锁就是表独占写锁,意思就是只有自己能够访问,
别的人不能访问。

元数据锁

什么是元数据锁?

元数据,英语缩写是MDL,在 MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作的时候,自动加 MDL 读锁;当要对表做结
构变更操作的时候,自动加 MDL 写锁。

注意:这个锁是自动提交的,要先开始事务,然后进行增删改查时,会自动加MDL读锁。

现在开始元数据锁的演示,大家跟着老刘一起练习。

1、session1开启事务,给表自动加读锁。

  1. session1: begin;
              select * from mylock;

2、session2对该表进行修改时就会造成阻塞。

  1. session2: alter table mylock add f int;

3、session1提交事务 或者 rollback 释放读锁 。

4、session2修改完成。

MySQL行级锁

MySQL的行级锁是由存储引擎实现的,利用存储引擎锁住索引项来实现,主要讲InnoDB行级锁。

InnoDB行级锁,按锁范围分为三种:

  • 记录锁:锁定索引中的一条记录。
  • 间隙锁:锁的是缝,要么锁住索引记录中间的值,要么锁住第一个索引记录前面的值或者最后一个索引记录后面的值。
  • Next-key locks:记录锁和间隙锁的组合(可以不看)

InnoDB行级锁,按功能分:

  • 共享读锁(S):手动添加,允许一个事务去读一行,其他事务可以读数据,但不能修改数据。

    1. SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE -- 共享读锁 手动添加
  • 排他写锁(X):自动添加,指的是一个事务在一行数据加上排他锁后,其他事务不能再在其上加其他的锁

InnoDB也实现了表级锁,也就是意向锁,意向锁是mysql内部使用的,不需要用户干预。

两阶段锁(2PL)

两阶段锁讲的是锁操作分为两个阶段:加锁阶段和解锁阶段。

加锁阶段:只加锁,不放锁。

解锁阶段:只放锁,不加锁。

行锁演示

InnoDB行锁是通过给索引上的索引项加锁来实现的,因此只有通过索引条件检索的数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!

行读锁

1、我们利用session1给id=1的行加读锁,使用索引。

  1. session1: begin;
              select * from mylock where ID=1 lock in share mode; 

2、由于行锁锁定的是行,所以利用session2修改别的行例如id=2是可以的,修改id=1就不行了。

  1. session2update mylock set name='M' where id=2;
    session2update mylock set name='M' where id=1;

3、当session1提交后,session2才可以修改。

  1. session1: commit; 
    session2update mylock set name='M' where id=1; 
    Query OK, 1 row affected (0.00 sec)
    Rows matched: 1 Changed: 1 Warnings: 0

关于行锁,我们要注意使用索引加行锁 ,未锁定的行可以访问。

行读锁升级为表锁

mylock表中id加了索引,name没有加索引,当我们对name加行读锁时,就会出现行读锁升级为表锁。

1、session1开启事务

  1. session1: begin;

2、手动加name='c'的行读锁,未使用索引

  1. select * from mylock where name='c' lock in share mode;

3、session2修改阻塞,未用索引行锁升级为表锁

  1. update mylock set name='N' where id=2;

4、session1提交事务或者 rollback 释放读锁

  1. commit;

5、session2就会修改成功

  1. update mylock set name='N' where id=2;

行写锁

1、session1开启事务并且手动加id=1的行写锁。

  1. session1: begin;
              select * from mylock where id=1 for update;

2、这里有一个特别重要的知识点,很多人会弄错!

排他锁锁住一行数据后,其他事务就不能读取和修改该行数据,其实不是这样的!

排他锁指的是一个事务在一行数据加上排他锁后,其他事务不能再在其上加其他的锁。MySQL InnoDB引擎默认的修改数据语句:update,delete,insert都会自动给数据加上排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使用select …for update语句,加共享锁可以使用select … lock in share mode语句。所以其他事务是不能修改加过排他锁的数据行,其他事务也不能通过for update和lock in share mode锁的方式查询数据,但可以直接通过select …from…查询数据,因为普通查询没有任何锁机制。

所以session2可以访问id=1的数据行。

  1. session2: select * from mylock where id=1 ;

3、但是不能给它继续加锁

  1. session2: select * from mylock where id=1 lock in share mode ;

4、session1提交事务或者rollback释放写锁,session2才会执行成功

间隙锁

根据检索条件向左寻找最靠近检索条件的记录值A,作为左区间,向右寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B)。根据图中where number=5的话,那么间隙锁的区间范围为(4,11);

间隙锁防止两种情况

  1. 防止插入间隙内的数据
  2. 防止已有数据更新为间隙内的数据

间隙情况:

  1. id、number均在间隙内
  2. id、number均在间隙外
  3. id在间隙内、number在间隙外
  4. id在间隙外,number在间隙内
  5. id、number为边缘数据

非唯一索引等值

  1. update news set number=3 where number=4;

检索条件number=4,向左取得最靠近的值2作为左区间,向右取得最靠近的5作为右区间,因此,session 1的间隙锁的范围(2,4),(4,5),即记录(id=1,number=2)和记录(id=3,number=4)之间间隙会被锁定,记录(id=3,number=4)和记录(id=6,number=5)之间间隙被锁定。

当我们添加数据时,结果如下:

  1. insert into news value(2,3);
    均在间隙内,阻塞
    insert into news value(7,8);
    均在间隙外,成功
    insert into news value(2,8);
    id在间隙内,number在间隙外,成功
    insert into news value(4,8);
    id在间隙内,number在间隙外,成功
    insert into news value(7,3);
    id在间隙外,number在间隙内,阻塞
    insert into news value(7,2);
    id在间隙外,number为上边缘数据,阻塞
    insert into news value(2,2);
    id在间隙内,number为上边缘数据,阻塞
    insert into news value(7,5);
    id在间隙外,number为下边缘数据,成功
    insert into news value(4,5);
    id在间隙内,number为下边缘数据,阻塞

我们可以得到只要number(where后面的)在间隙里(2 3 4),不包含最后一个数(5)则不管id是多少都会阻塞。 如果是下边缘数据需要看id是否在间隙内。

主键索引范围

由于主键不能重复,所以id无边缘数据。

  1. update news set number=3 where id>1 and id <6;
  1. insert into news value(2,3);
    均在间隙内,阻塞
    insert into news value(7,8);
    均在间隙外,成功
    insert into news value(2,8);
    id在间隙内,number在间隙外,阻塞
    insert into news value(4,8);
    id在间隙内,number在间隙外,阻塞
    insert into news value(7,3);
    id在间隙外,number在间隙内,成功

我们可以得到只要id(在where后面的)在间隙里(2 4 5),则不管number是多少都会阻塞。

非唯一索引无穷大

  1. update news set number=3 where number=13 ;
  1. insert into news value(11,5);
    执行成功
    insert into news value(12,11);
    执行成功
    insert into news value(14,11);
    阻塞
    insert into news value(15,12);
    阻塞

检索条件number=13,向左取得最靠近的值11作为左区间,向右由于没有记录因此取得无穷大作为右区间,因此,session 1的间隙锁的范围(11,无穷大),当id和number同时满足 ,才会阻塞。

死锁

两个 session 互相等等待对方的资源释放之后,才能释放自己的资源,造成了死锁,主要是顺序出现问题。

我们session1先给id=1加锁,session2再给id=2加锁,此时session1想再给id=2加锁,但session2已经给它加锁了,就会造成死锁。

如何解决死锁?

MySQL默认会主动探知死锁,并回滚某一个影响最小的事务,等待另一个事务执行完成之后,再重新执行该事务。

总结

本文作为大数据开发指南MySQL的第三篇详细介绍了MySQL锁的内容,希望大家能够跟着老刘的文章,好好捋捋思路,争取能够用自己的话把这些知识点讲述出来!

尽管当前水平可能不及各位大佬,但老刘会努力变得更加优秀,让各位小伙伴自学从此不求人!

大数据开发指南地址如下:

  • github:https://github.com/BigDataLaoLiu/BigDataGuide
  • 码云:https://gitee.com/BigDataLiu/BigDataGuide

如果有相关问题,联系公众号:努力的老刘。文章都看到这了,点赞关注支持一波!

精通MySQL之锁篇的更多相关文章

  1. 精通MySQL之架构篇

    老刘是即将找工作的研究生,自学大数据开发,一路走来,感慨颇深,网上大数据的资料良莠不齐,于是想写一份详细的大数据开发指南.这份指南把大数据的[基础知识][框架分析][源码理解]都用自己的话描述出来,让 ...

  2. 精通MySQL之索引篇,这篇注重练习!

    老刘是即将找工作的研究生,自学大数据开发,一路走来,感慨颇深,网上大数据的资料良莠不齐,于是想写一份详细的大数据开发指南.这份指南把大数据的[基础知识][框架分析][源码理解]都用自己的话描述出来,让 ...

  3. 【mysql】- 锁篇(下)

    InnoDB存储引擎中的锁 表级锁 表级别的S锁.X锁 在对某个表执行SELECT.INSERT.DELETE.UPDATE语句时,InnoDB存储引擎是不会为这个表添加表级别的S锁或者X锁的 表级别 ...

  4. 【分布式锁的演化】“超卖场景”,MySQL分布式锁篇

    前言 之前的文章中通过电商场景中秒杀的例子和大家分享了单体架构中锁的使用方式,但是现在很多应用系统都是相当庞大的,很多应用系统都是微服务的架构体系,那么在这种跨jvm的场景下,我们又该如何去解决并发. ...

  5. 【mysql】- 锁篇(上)

    回顾 问题 事务并发执行时可能带来各种问题,并发事务访问相同记录的情况大致可以划分为3种 读-读情况:即并发事务相继读取相同的记录 读取操作本身不会对记录有什么影响,并不会引起什么问题,所以允许这种情 ...

  6. mysql 开发进阶篇系列 6 锁问题(事务与隔离级别介绍)

    一.概述 在数据库中,数据是属于共享资源,为了保证并发访问的一致性,有效性,产生了锁.接下来重点讨论mysql锁机制的特点,常见的锁问题,以及解决mysql锁问题的一些方法或建议. 相比其他数据库,m ...

  7. MYSQL(基本篇)——一篇文章带你走进MYSQL的奇妙世界

    MYSQL(基本篇)--一篇文章带你走进MYSQL的奇妙世界 MYSQL算是我们程序员必不可少的一份求职工具了 无论在什么岗位,我们都可以看到应聘要求上所书写的"精通MYSQL等数据库及优化 ...

  8. 【MySQL】锁入门

    要做的完全掌握MySQL/InnoDB的加锁规则,甚至是其他任何数据库的加锁规则,需要具备以下的一些知识点 了解数据库的一些基本理论知识:数据的存储格式 (堆组织表 vs 聚簇索引表):并发控制协议 ...

  9. mysql行锁和表锁

    mysql innodb支持行锁和表锁,但是MyIsam只支持表锁.现在我们说说mysql innodb的行锁和 有如下表id为主键 为了出现演示效果,我们将mysql的autocommit设置为0 ...

随机推荐

  1. mysql中order by优化的那些事儿

    为了测试方便和直观,我们需要先创建一张测试表并插入一些数据: CREATE TABLE `shop` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '记 ...

  2. 【vue】入门介绍

    一.前端开发工具vscode 前端代码编写工具,使用vscode:vscode官网 安装好之后,可以先装如下几个插件,方便后续的开发. 二.编写代码 1.vscode快捷键生成html代码 在vsco ...

  3. [leetcode]222. Count Complete Tree Nodes完全二叉树的节点数

    /* 满二叉树的特点是2^n-1,对于完全二叉树,一个node如果左右子树深度相同,那么 是一个满二叉树.如果不是,那就把node算上,继续往下看,下边的可能是满二叉树 由于完全二叉树中有一些子满二叉 ...

  4. 算法图解第一章_二分查找_python

    什么是二分查找? 我们先玩一个游戏. 在1至100之间我写下一个数,由你来猜测这个数是多少.我会告诉你高了还是低了. 最简单的办法就是每次取一半. 例如 "50""低了& ...

  5. node-sass 安装失败报错的原因及解决办法(整理)

    npm install 时偶尔遇到报错:没有安装python或node-sass 安装失败的问题,百度之后发现是被墙了,但根据百度的方法换了淘宝镜像和用了vpn都安装失败,最后发现原来是因为没有卸载之 ...

  6. [学习笔记]Golang--基础数据类型

    1,不同类型的变量不能互相赋值或者操作,如var a int8 = 16var b int = 23c := a + b 会报错,且int虽然默认32位,但和int32是不同的类型 iota只在声明枚 ...

  7. idea启动build过慢

    原文链接http://zhhll.icu/2020/04/17/idea/idea%E4%B9%8B%E7%BC%96%E8%AF%91%E9%97%AE%E9%A2%98/ 之前使用idea的时候每 ...

  8. 写给小白看的Mysql事务

    1 为什么需要事务 在网上的很多资料里,其实没有很好的解释为什么我们需要事务.其实我们去学习一个东西之前,还是应该了解清楚这个东西为什么有用,硬生生的去记住事务的ACID特性.各种隔离级别个人认为没有 ...

  9. 【Java基础】Eclipse 和数组

    Eclipse 和数组 Eclipse 安装和使用 ... 数组的概述 数组(Array):是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理. 数组相 ...

  10. 【JavaWeb】Cookie&Session

    Cookie&Session Cookie 什么是 Cookie Cookie 即饼干的意思 Cookie 是服务器通知客户端保存键值对的一种技术 客户端有了 Cookie 后,每次请求都发送 ...