美文网首页MySQL
MySQL 锁——No.2 MyISAM 与 InnoDB 锁方

MySQL 锁——No.2 MyISAM 与 InnoDB 锁方

作者: lframe | 来源:发表于2020-07-05 12:56 被阅读0次

    为什么要了解 MyISAM 与 InnoDB 锁方面的区别

    1. InnoDB 默认支持行级锁,而 MyISAM 默认支持表级锁
    2. 表级锁会锁表
    1) 即当对数据进行 select 操作对时候,它会自动为表加一个表级的读锁;
    2) 当对数据增删改的时候,它会自动为我们加一个表级别的写锁;
    当一个表的读锁未被释放时,另一个 session 想要对同一张表加写锁时就会被阻塞,直到所有对读锁被释放;
    反之先写后读同样会被阻塞
    3. 行级锁并不会锁表,即使是针对同一行数据,增删改操作也不会阻塞读操作
    4. 如果不了解 InnoDB 关于锁方面的原理,某些操作仍然会导致锁表,造成性能急剧下降

    MyISAM 与 InnoDB 关于锁方面的区别.png

    InnoDB 的锁演示

    1. 为了演示 InnoDB 锁的原理,首先关闭自动提交
    InnoDB 默认为自动提交,即在执行一个 SQL 的时候,它会自动提交,我们可以通过 show variables like "autocommit"; 查看是否为自动提交.

    查看是否为自动提交

    2. 为了演示 InnoDB 锁的原理,首先关闭自动提交set autocommit = off;【该命令只能关闭当前会话的】【当然,我们可以不用改配置,在执行相应SQL之前,使用begin transaction开启事务即可,在需要提交的时候,再commit】

    关闭自动提交
    自动提交本质上是 Innodb 使用了二段锁,加锁和解锁是分为两个步骤进行的,即先对同一个事务里面的一批操作分别进行加锁,然后到 commit 的时候,再对事务里面加的锁统一解锁

    非阻塞读演示【读操作不会阻塞增删改操作】

    1. 整体表结构如下

    image.png

    2. 首先在会话1中读取一下"person_info_large"表id=3的数据,但不提交

    image.png

    3. 在另一个会话中同样对 id=3 对数据进行修改操作,也不提交【从结果可以看出,对同一行对读操作并没有阻塞当前更新操作】【是因为 InnoDB 的 select 并没有对该行上锁,即是 InnoDB 的非阻塞 select特性】

    image.png

    读上锁演示【读操作上锁会阻塞增删该操作】

    1. 在一个会话中读取id =3 的数据时,加读锁;使用【lock in share mode】

    image.png
    2. 在另一个会话中,修改该行数据,【会被阻塞】,即只有第一个会话提交后,第二个会话中才能获得锁
    image.png

    InnoDB 支持行级锁演示 【同行的修改操作会相互阻塞,不同行的修改不会相互阻塞【上锁的读在同一行操作时,也会相互阻塞】】

    1. 先演示同行的修改操作会相互阻塞,两个会话同时修改ID=4的数据
    1) 会话1的操作

    image.png
    2) 会话2的操作会被阻塞
    image.png
    2. 不同行的修改操作不会阻塞

    1)会话 1 的操作

    image.png
    2)会话2的操作【可以看到,会话2的修改不同行的操作时,并不会被阻塞,因此可以得出 InnoDB 可以支持行级锁】
    image.png
    即 InnoDB 默认支持行级锁;并且 select、update 同一行数据的时候,select 并不阻塞 update 操作,update 操作也不阻塞 select 操作

    从上面到演示中可以看到,检索条件都使用的是主键索引,那行级锁是否和索引有关呢?

    这里先给出结论,后面做演示:

    1. 除主键索引以外的其他键,如唯一索引、普通索引,只要 SQL 用到索引,涉及的行都会被上共享锁和排它锁

    2. InnoDB 当不走索引的时候,整张表就会被锁住,也就是说此时用的是表级锁;因此 InnoDB 在 SQL 没有用到索引的时候,用的是表级锁,而 SQL 用到索引的时候,用的是行级锁以及 gap 锁【gap 锁在走普通非唯一索引时使用,后面会有单独文章分析】

    3. InnoDB 除支持行级锁外,还支持表级的意向锁,意向锁也分为共享读锁(IS),还有排它写锁(IX),和myisam的表锁差不多。主要是为了表级别的操作的时候不用轮询每一行看看有没有上行锁。

    演示

    从下图中可以看出,name 字段没有索引,我们就以name字段进行演示


    image.png

    我们就使用id =1和id=2的name进行演示,两个name不同


    image.png

    1)会话 1 更新id=1 的行数据


    image.png
    1. 会话2 更新id = 2 的行数据【此时,我们本身更新的是不同行的数据,但是会话2仍然被阻塞了,即 InnoDB 在不走索引的时候,整张表都会被锁住,】


      image.png

    innodb默认是行级锁,也支持表级锁,而myisam默认支持表级锁,但不支持行级锁;无论是表级锁还是行级锁,都分为共享锁和排它锁。

    MyISAM 的锁

    关于 MyISAM 的锁就不演示了,现阶段日常开发我们也不会使用 MyISAM 引擎,这里仅介绍其特性

    1. MyISAM默认用的是表级锁,不支持行级锁。
    2. 读操作和写操作相互之间会阻塞
    3. 写操作之间也会阻塞
    4. 读操作之间不会阻塞

    共享锁和排它锁的兼容性

    X 排它锁;增删改操作会上排他锁
    S 共享锁

    \ X S
    X 冲突 冲突
    S 冲突 冲突

    增删改或者select for update 都会上排它锁。如果一个session对一行记录上了排它锁,则另一个session对这行记录上排它锁时,会冲突,必须等第一个session释放了锁,才能上锁。而如果另一个session对这行记录上共享锁,也是冲突的。如果一个session对一行记录上共享锁,另一个session对这行记录上上排它锁是,会冲突,必须等第一个session释放了锁,才能上锁。而如果另一个session对这行记录上共享锁,此时是不冲突的。

    MyISAM 和 InnoDB 分别适用的场景

    MyISAM

    1. 频繁执行全表count语句。【因为MYISAM用一个变量保存了整个表的行数,而Innodb执行该语句时需要从新扫描表进行统计】
    2. 对数据进行增删改的频率不高,查询非常频繁
    3. 没有事务

    InnoDB

    1. 数据增删改查都相当频繁。【增删改的时候,只是某些行被锁,早大多数情况下避免了阻塞,而不像myisam对某行的增删改,都会锁住整张表】
    2. 可靠性要求比较高,要求支持事务

    行级锁是不是一定比表级锁要好?
    未必,锁的粒度越细,代价越高,相比表级锁在表的头部直接加锁,行级锁还需要扫描
    某行的时候对齐上锁,这样代价比较大,Innodb支持事务的同时,也相比MyISAM引擎带来了更大的开销,同时,在之前的索引部分也了解到,Innodb 必须有且仅有一个聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高,但是辅助索引需要查两次,先查到主键,再通过主键查询到数据,而MyISAM 是非聚集索引,数据和文件是分离的,索引保存的时候数据文件的指针,主键索引和辅助索引是独立的,因此 MyISAM 引擎在纯检索系统中【增删改很少的系统中】其性能要好于Innodb。

    数据库锁的分类

    按锁粒度划分

    可分为表级锁、行级锁、页级锁。innodb默认支持行级锁,同时也支持表级锁,innodb对行级上锁的时候,会先上一种表级别的意向锁。】【myisam仅支持表级锁。】

    按锁级别划分

    可分为共享锁、排它锁

    按加锁方式划分

    可分为自动锁、显式锁【像意向锁、还有myisam的表锁、以及update、insert、delete的时候,加上的锁就是自动锁,因为这是mysql自动为我们上的。而select for update 、lock share mode 这些我们显式加的锁就是显式锁了】

    按操作划分

    可分为DML锁、DDL锁【对数据进行操作上的锁就称为DML锁(包括对数据的增删改查),而对表结构进行变更的,如alter table这些语句,加上的锁就是DDL锁】

    按使用方式划分

    可分为乐观锁、悲观锁。
    1. 悲观锁
    悲观锁是先取锁再访问的策略,为数据处理的安全提供了保证,但是在效率方面,处理加锁的机制,会让数据库产生额外的开销,还有增加产生死锁的机会,另外在只读型事务处理中,由于不会产生冲突,也没有必要使用锁。如果上锁,会增加系统负担,还会降低并行性,如果一个事务锁定了某行数据,其他事务就必须等待该事务处理完,才可以去处理
    多session的互锁操作,就是悲观锁的实现
    2. 乐观锁
    而乐观锁认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会对数据的冲突与否进行检测,如果冲突了,则返回用户错误的信息,让用户决定如何去做。相对于悲观锁,乐观锁并不会使用数据库提供的锁机制【一般乐观锁的实现是记录数据的版本,实现版本有两种方式,第一个是使用版本号,第二种是使用时间戳】
    使用版本号是基于数据版本的,即version记录机制的实现方式。
    何为数据版本,即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的version字段实现。
    即我们对数据每更新一次,该version字段的值就加1,当我们提交更新的时候,去判断数据库表对应记录的当前版本信息,与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据

    相关文章

      网友评论

        本文标题:MySQL 锁——No.2 MyISAM 与 InnoDB 锁方

        本文链接:https://www.haomeiwen.com/subject/qcgmqktx.html