MySQL-锁

微笑、不失礼 提交于 2020-01-14 22:07:13

MySQL-锁

  • 锁的分类

    • 按照功能分

      共享锁(读锁/S锁) 其他不可获得X锁 所有连接均可读取,所有连接均不可修改
      排他锁(写锁/X锁) 其他不可获得S/X锁 加锁连接可以读取可以修改,其他连接均不可读写
    • 按照锁的粒度分

      • 全局锁表锁行锁等…
  • 全局锁

    • MySQL全局锁会使用读锁锁定所有库中所有的表
    • 加锁:FLUSH TABLES WITH READ LOCK;
    • 解锁:UNLOCK TABLES;
    • 全局锁加锁后,所有的连接只能读表,加锁的连接进行表中数据的修改会报错。其他连接进行数据修改会阻塞,直到全局锁解锁后返回。一般用在整个库做备份时。
  • 表锁

    • MySQL表锁在事务需要更新大表的大部分或全部数据时。如果使用行锁加锁效率极低,因此这种情况下一般使用表锁,事务涉及多个表时可能会因此死锁,也可以考虑使用表锁来避免死锁。

    • 表锁分为表读锁表写锁

      • 表读锁

        • lock tables t read;
        • 表读锁时所有连接都可以读,本连接修改会报错,其他连接修改会阻塞,直到锁释放才返回。
      • 表写锁

        • lock tables t write;
        • 表写锁时,本连接可以读和写,其他连接会阻塞,直到锁释放后返回。
  • 行锁

    • InnoDB比MyISAM具有的优势主要是支持事务,以及支持行锁。

    行共享锁 允许所有事务去读加锁行,阻止其他事务获得相同行的排他锁。
    行排他锁 只允许加锁的事务去读写,阻止其他事务获得共享锁或排他锁。
    • 快照读与当前读

      快照读 不显式加锁的select语句 不加任何锁
      当前读 显示加锁的select与insert、delete、update 加排他锁
      • 显式加锁

        • 共享锁:select * from table_name lock in share mode;
        • 排他锁:select * from table_name for update;
      • 不显式加锁时select不会加锁,且select也可以读取加了锁的行,因为每行数据有多个版本,每次select只需读取其中的数据即可,RC级别下读取最新的数据,RR级别下读取事务开始前的数据,通过MVCC实现。

    • 加锁方式

      • InnoDB行锁的加锁方式有三种:

      • Record Lock 单个记录上的索引加锁。
        Gap Lock 间隙锁,所索引项之间的间隙加锁,不包括记录本身。
        Next-Key Lock 锁定一个范围,并缩定记录本身,相当于Record+Gap Lock。
    • 加锁方式选择

      • 通过非索引字段查询时加锁:
        • 对整个表加表锁,其他连接对表中所有行均不可以修改。
      • 通过唯一索引字段查询时加锁:
        • 对聚族索引和此索引中的此行均加锁。
      • 通过非唯一索引字段查询时加锁:
        • 满足条件的行在此索引和聚族索引中均加锁。
  • 间隙锁

    • 在RC级别下会产生幻读(事务中两次读取到的数据行数不同),因为行锁只锁定了当前存在的匹配的行,因此其他事务仍可以插入相同值的新行。导致了RC级别下第一次select查询时对同一key值的所有行加锁,而其他事务仍可以插入key值相同的新行,因此第二次select查询时会导致幻读读到新的行。

    • 但在RR级别下,会加入间隙锁,间隙锁会锁定加锁的key值的所有间隙,使其他连接不能插入同key的新行。

    • 间隙锁是在RR隔离级别下的,避免了RC级别下存在的当前读幻读问题,当前读会维护所有的索引在其中判断是否含有间隙锁。

    • 无索引

      • 当使用非索引字段时,会把所有行都加上行排他锁,所有的间隙都加上间隙锁,使其他插入更新等均不可执行。(是否会退化成行锁呢?)
    • 唯一索引

      • 唯一索引不存在插入同一key的情况,因此不会发生幻读无需加间隙锁。
    • 普通索引

      • 当使用普通索引字段时,把匹配的key的所有行都加上行排他锁,并在key的间隙加上间隙锁,使其他连接无法插入同key的新行。
    • MVCC和间隙锁

      • 在RR级别中,MySQL通过MVCC来解决快照读时的幻读问题,间隙锁解决当前读下的幻读问题。
  • 元数据锁

    • 在之前MySQL事务与DDL(ALERT、DROP等)一同对一张表操作时会出现问题。因此引入了元数据锁(MDL)。

    • 在语句或事务执行时,会对表加上元数据锁,使其他连接在事务结束之前DDL语句操作此表时将阻塞,直到结束后才进行操作并返回。

  • 元数据锁导致的阻塞

    • 在有多个连接对此表进行操作时,如果有连接正在进行事务或语句,而一个连接正在为了抢夺这个连接的MDL锁来进行DDL操作而阻塞时,其他查询连接将也阻塞在此,直到ddl进行结束,或者阻塞ddl的连接被断开。
    • 因此应尽量避免慢查询以及事务应即使提交,且避免在业务高峰期进行DDL操作。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!