• 《MySQL数据库》MySQL锁分析


    前言

    作者在工作中遇到了往MySQL表中插入一条数据,结果插入不进去。并且同样的操作在Oracle中却可以插入,于是就专门研究了一下MySQL5.7锁的逻辑。

    锁的介绍

    介绍锁之前需要先了解一下事务隔离级别:https://www.cnblogs.com/jssj/p/13437036.html

    MySQL 主要锁类型如下

    (1)共享/排它锁(Shared and Exclusive Locks)

    共享锁:select ...... lock in share mode;   其他事务无法修改,发送在读取操作。

    排它锁:select ...... for update;    其他事务无法修改,发生新增修改操作

    (2)意向锁(Intention Locks)

    就是从行锁升级到表锁。

    (3)记录锁(Record Locks)

    对记录行进行更新操作时候的一种锁,防止事务1更新的时候,事务2也更新,导致最终数据问题。

    (4)间隙锁(Gap Locks)

    范围更新数据的时候,将这些范围里面数据中间的间隙也不能被修改或者插入。比如更新主键id 10 到 100 之前的数据,这个时候其他事务是无法插入 id等 10到100之间的记录的。

    (5)临键锁(Next-key Locks)

    将行锁和间隙锁结合:将间隙和大于目前索引值的全部锁定,不让其他事务插入。

    (6)插入意向锁(Insert Intention Locks)

    插入意向锁是一种特殊的间隙锁,但不同于间隙锁的是,该锁只用于并发插入操作。如果说间隙锁锁住的是一个区间,那么插入意向锁锁住的就是一个点。

    (7)自增锁(Auto-inc Locks)

    AUTO-INC LOCKS是一种表级别锁,当一个表格中存在AUTO_INCREMENT列,事务尝试在该表中插入记录时,会使用该中特殊的表级别锁。最简单的场景是,当A事务试图在该表中插入记录时,其他试图在该表中插入记录的事务必须等待A事务,以使A事务插入的记录获得连续的主键。

    innodb_autoinc_lock_mode这个设置控制了Mysql使用何种算法进行auto-increment lock

    我们看一个案例:

    创建一张表:

    CREATE TABLE test(id int primary key not null auto_increment, name VARCHAR(128));

    插入一些数据

    insert into test(name) VALUES('lili');
    insert into test(name) VALUES('zhangsan');
    insert into test(name) VALUES('leilei');
    insert into test(name) VALUES('lisi');
    insert into test(name) VALUES('wangwu');
    insert into test(name) VALUES('zhaoliu');

    测试:在一个地方开启事务,然后删除表数据并且不提交。

    另外开启一个窗口,测试新增语句:

    等待超时无法提交,在等待结束之前我们来看看mysql 给我们提供的锁表信息

    select * from information_schema.innodb_trx t;           -- 当前运行的所有事务 
    select * from information_schema.innodb_locks t;         -- 当前出现的锁
    select * from information_schema.innodb_lock_waits t;    -- 锁等待的对应关系

     

    innodb_trx 显示运行事务的情况,很明显有两个事务在运行,其中被锁事务的sql可以展示。 

    innodb_locks  该表比较重要的信息为,可以为我们提供两个事务为什么会互斥导致出现锁, 比如字段 lock_mode 是指具体的锁类型,X表示互斥锁,GAP表示间隙锁

     

    innodb_lock_waits  该表给我展示的是互斥资源之间的关系。

    这三张表各个字段含义:

    innodb_trx

    innodb_locks  

    innodb_lock_waits

    案例

    我们在进行修改表的ddl 操作时:发现会一直执行下面,不会停止。

    通过:show processlist;

    会出现:Waiting for table metadata lock,在等待锁的释放。

    等待时间参数:

    select @@lock_wait_timeout;

    可以通过查询:

    select * from information_schema.innodb_trx;

    来找到running 的记录并且 kill trx_mysql_thread_id ;  生产需要谨慎使用,因为这边是不知道别kill掉的是什么?

    下面在测试一个案例(该演示不要使用第三方工具例如Navicat 等):

    一个窗口删除数据,不提交。

    另外一个窗口,更新这条记录,会出现锁等待。

    这个时候我们查询mysql的`performance_schema`.events_statements_current 表可以看到sql语句的执行情况。

    如果生产数据量大的话其实也是不好排查的。

    将mysql 表关联起来找到引起锁等等待的事务语句

    SELECT r.trx_id waiting_trx_id,
        r.trx_mysql_thread_id waiting_thread,
        r.trx_query waiting_query,
        b.trx_id blocking_trx_id,
        b.trx_mysql_thread_id blocking_thread,
        b.trx_query blocking_query
    FROM information_schema.innodb_lock_waits w
    INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
    INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;

    将图中449作为下面sql的条件:

    SELECT a.sql_text,
        c.id,
        d.trx_started
    FROM `performance_schema`.events_statements_current a
    JOIN `performance_schema`.threads b ON a.thread_id = b.thread_id
    JOIN information_schema.`PROCESSLIST` c ON b.processlist_id = c.id
    JOIN information_schema.innodb_trx d ON c.id = d.trx_mysql_thread_id
    WHERE 1 = 1 and c.id = 449    -- blocking_thread 编号
    ORDER BY d.trx_started;

    这样我们就找到了是什么sql语句没有提交事务,导致锁等待的出现。

    总结

    MySQL查询未提交事务的目前知晓的是一定要出现锁等待才能查到,不然就获取不到未提交事务的执行情况,如果有人知道请一定要分享给我,谢谢。

  • 相关阅读:
    AI CV 会议2018
    ubuntu 更改默认亮度
    ubuntu安装latex
    过滤文件代码 python
    ubuntu安装pycharm桌面快捷方式
    Ubuntu 14.04 鼠标消失解决方案
    ffmpeg常用命令
    FFMPEG 在ubuntu下的安装与使用
    pragma once
    chrono--高精度计时
  • 原文地址:https://www.cnblogs.com/jssj/p/13466294.html
Copyright © 2020-2023  润新知