MySQL 事务隔离级别与锁机制详解

news2024/11/21 2:33:31

目录

    • 一、前言
    • 二、事务及其ACID属性
    • 三、并发事务处理带来的问题
    • 四、事务隔离级别
      • 4.1、隔离级别分类
      • 4.2、查看当前数据库的事务隔离级别:
      • 4.3、临时修改数据库隔离级别(重启MySQL后恢复到配置中的级别)
    • 五、表数据准备
    • 六、MySQL常见锁介绍
      • 5.1、锁分类
      • 5.2、表锁
      • 5.3、共享锁 (lock in share mode) 和 排它锁(for update)
      • 5.4、行锁
      • 5.5、间隙锁(Gap Lock)
      • 5.6、临键锁(Next-key Locks)
    • 七、行锁与事务隔离级别案例分析
      • 7.1、读未提交(READ UNCOMMITTED)案例分析
      • 7.2、读已提交(READ COMMITTED)案例分析
      • 7.3、可重复读(REPEATABLE READ)案例分析
      • 7.4、串行化(SERIALIZABLE)案例分析
    • 八、其它问题
      • 8.1、无索引行锁会升级为表锁
        • 8.1.1、问题复现
        • 8.1.2、问题解决
      • 8.2、死锁问题
        • 8.2.1、死锁问题复现
        • 8.2.2、问题解决
      • 8.3、行锁分析
      • 8.4、查看锁和事务信息

一、前言

      我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增删改查操作,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。
      这些问题的本质都是数据库的多事务并发问题,为了解决多事务并发问题,数据库设计了事务隔离机制、锁机制、MVCC多版本并发控制隔离机制,用一整套机制来解决多事务并发问题,接下来,会深入这些机制分析数据库内部的执行原理。
      这里都会以 InnoDB 引擎来做讲解。

二、事务及其ACID属性

事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性。

  • 原子性(Atomicity) :事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
  • 一致性(Consistent) :在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性。
  • 隔离性(Isolation) :数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
  • 持久性(Durable) :事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

三、并发事务处理带来的问题

  • 更新丢失(Lost Update)或脏写
    当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。
  • 脏读(Dirty Reads)
    一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致的状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此作进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象的叫做“脏读”。例如:事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求。
  • 不可重读(Non-Repeatable Reads)
    一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读”。例如:事务A内部的相同查询语句在不同时刻读出的结果不一致,不符合隔离性
  • 幻读(Phantom Reads)
    一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。例如:事务A读取到了事务B提交的新增数据,不符合隔离性

四、事务隔离级别

“脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制
来解决。

4.1、隔离级别分类

隔离级别脏读(Dirty Reads)不可重读(Non-Repeatable Reads)幻读(Phantom Reads)
读未提交(READ UNCOMMITTED)可能可能可能
读已提交(READ COMMITTED)不可能可能可能
可重复读(REPEATABLE READ)不可能不可能可能
串行化(SERIALIZABLE)不可能不可能不可能
  • 脏读:事务A读取到了事务B已经修改但尚未提交的数据。
  • 不可重读:事务A内部的相同查询语句在不同时刻读出的结果不一致,不符合隔离性。
  • 幻读:一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。 事务A读取到了事务B提交的新增数据,不符合隔离性。

      数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。
      同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读"和“幻读”并不敏感,可能更关心数据并发访问的能力。

4.2、查看当前数据库的事务隔离级别:

  • MySQL5.7查看事务隔离级别
## 查看MySQL配置中的事务隔离级别
SHOW VARIABLES LIKE 'tx_isolation';
## 查询MySQL全局事务隔离级别
SELECT @@GLOBAL.tx_isolation;
## 查询MySQL当前会话事务隔离级别
SELECT @@SESSION.tx_isolation;
  • MySQL8.0查看事务隔离级别
## 查看MySQL配置中的事务隔离级别
SHOW VARIABLES LIKE 'transaction_isolation';
## 查询MySQL全局事务隔离级别
SELECT @@GLOBAL.transaction_isolation;
## 查询MySQL当前会话事务隔离级别
SELECT @@SESSION.transaction_isolation;

两个版本数据库默认级别都是可重复读(REPEATABLE READ)。

4.3、临时修改数据库隔离级别(重启MySQL后恢复到配置中的级别)

# 设置全局隔离级别
set global transaction isolation level READ UNCOMMITTED;
set global transaction isolation level READ COMMITTED;
set global transaction isolation level REPEATABLE READ;
set global transaction isolation level SERIALIZABLE;
#设置会话隔离级别 
set session transaction isolation level READ UNCOMMITTED;
set session transaction isolation level READ COMMITTED;
set session transaction isolation level REPEATABLE READ;
set session transaction isolation level SERIALIZABLE;

五、表数据准备

这里准备一张账户表用于后续测试

# 创建表
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
 `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
 `name` VARCHAR ( 255 ) DEFAULT NULL,
 `balance` INT ( 11 ) DEFAULT NULL,
 PRIMARY KEY ( `id` ) 
) ENGINE = INNODB COMMENT = '账户表';
# 插入数据
INSERT INTO `account` (`id`,`name`, `balance`) VALUES (1,'Kerwin',1000);
INSERT INTO `account` (`id`,`name`, `balance`) VALUES (2,'Alia',800);
INSERT INTO `account` (`id`,`name`, `balance`) VALUES (3,'Ross',900);

六、MySQL常见锁介绍

先确定MySQL的事务隔离级别为默认的可重复读(REPEATABLE READ),如果不是先将事务隔离级别修改成可重复读(REPEATABLE READ),不同隔离级别锁机制有区别避免出现和下面示例不一致的情况。

5.1、锁分类

  • 从业务上分为乐观锁(用版本对比来实现)和悲观锁
  • 从对数据库操作的类型来分,分为读锁和写锁(都属于悲观锁)
    • 读锁(共享锁,S锁(Shared)):针对同一份数据,多个读操作可以同时进行而不会互相影响
    • 写锁(排它锁,X锁(eXclusive)):当前写操作没有完成前,它会阻断其他写锁和读锁
  • 从对数据操作的粒度分,分为表锁和行锁

5.2、表锁

      每次操作锁住整张表。开销小,加锁快;不会出现死锁,锁定粒度大,发生锁冲突的概率最高,并发度最低,一般用在整表数据迁移的场景。

表锁分为读锁和写锁

  • 添加读锁

    # 添加读锁
    lock table account read;
    

    当前session和其他session都可以读该表,当前session中插入或者更新锁定的表都会报错,其他session插入或更新则会等待。

  • 添加写锁

    # 添加写锁
    lock table account write;
    

    当前session对该表的增删改查都没有问题,其他session对该表的所有操作被阻塞。

  • 查看表锁

    # 查看是否有锁表
    show open tables where in_use > 0;
    # 查看account表
    show open tables like 'account';
    
  • 释放表锁

    # 当前session添加的锁
    unlock tables;
    

5.3、共享锁 (lock in share mode) 和 排它锁(for update)

  • 共享锁(读锁S):针对同一份数据,多个读操作可以同时进行而不会互相影响

    # 给id为1的数据添加共享锁
    select * from account where id=1 lock in share mode;
    
  • 排它锁(写锁X):当前写操作没有完成前,它会阻断其他写锁和读锁

    # 给id为1的数据添加排它锁
    select * from account where id=1 for update;
    

5.4、行锁

      每次操作锁住一行数据,开销大,加锁慢,会出现死锁,锁定粒度最小,发生锁冲突的概率最低,并发度最高,InnoDB在执行查询语句SELECT时(非串行隔离级别),不会加锁。但是update、insert、delete操作会加行锁。
      InnoDB的行锁是针对索引加的锁,不是针对记录加的锁,只有where条件中的列有索引时才会使用行锁,无索引行锁会升级为表锁,这一点会在后面讲解。

行锁演示:
要演示行锁要开启三个session,MySQL事务默认是自动开启自动提交的,这里会用begin;commit;关键字控制事务的开启和提交。

  • session1 先开启一个事务执行给id为1的用户添加100,先不提交事务

    begin;
    update account set balance = balance + 100 where id = 1;
    
  • session2 先查询看一下id为1的用户数据

    select * from account where id = 1;
    

    在这里插入图片描述
    这里可以看到数据余额还是1000

  • session2 也执行一次给id为1的用户添加100

    update account set balance = balance + 100 where id = 1;
    

    在这里插入图片描述
    这里可以看到session2中给id为1的用户添加100阻塞住了。

  • session2 执行一次给id为2的用户添加100

    update account set balance = balance + 100 where id = 2;
    

    在这里插入图片描述
    这里可以看到session3中给id为2的用户添加100立马执行成功了。

  • 提交session1的事务

    # 在session1执行提交事务
    commit;
    

    session1提交事务后,session2更新数据成功耗时32.369s,也就是说session1在更新id为1的数据时上了锁,在提交事务后锁被释放了,session2才能执行id为1的数据的更新。
    在这里插入图片描述

5.5、间隙锁(Gap Lock)

间隙锁,锁的就是两个值之间的空隙,MySQL默认级别是可重复读(REPEATABLE READ),间隙锁在某些情况下可以解决幻读问题,间隙锁是在可重复读隔离级别下才会生效。

假设account表里数据如下:
在这里插入图片描述
那么间隙就有 id 为 (3,10),(10,20),(20,正无穷) 这三个区间,
在session1下面执行 update account set name = ‘Linda2’ where id > 8 and id <18;,则其他session没法在这个范围所包含的所有行记录(包括间隙行记录)以及行记录所在的间隙里插入或修改任何数据,即id在(3,20]区间都无法修改数据,注意最后那个20也是包含在内的。

5.6、临键锁(Next-key Locks)

Next-Key Locks是行锁与间隙锁的组合。像上面那个例子里的这个(3,20]的整个区间可以叫做临键锁。

七、行锁与事务隔离级别案例分析

7.1、读未提交(READ UNCOMMITTED)案例分析

  • 1、打开一个客户端A,并设置当前session事务模式为读未提交(READ UNCOMMITTED),查询表account的初始值。

    ## 设置当前session事务隔离级别为读未提交(READ UNCOMMITTED)
    set session transaction isolation level READ UNCOMMITTED;
    ## 开启事务
    begin;
    ## 查询表account的初始值
    select * from account;
    

    在这里插入图片描述

  • 2、在客户端A的事务提交之前,打开另一个客户端B并且也设置当前session事务模式为读未提交(READ UNCOMMITTED),给表account中id为1的数据添加50。

    ## 设置当前session事务隔离级别为读未提交(READ UNCOMMITTED)
    set session transaction isolation level READ UNCOMMITTED;
    ## 开启事务
    begin;
    ## 给表account中id为1的数据添加50
    update account set balance = balance + 50 where id = 1;
    ## 查询id为1的数据
    select * from account where id = 1;
    

    在这里插入图片描述

  • 3、客户端A中查询表account中id为1的数据,虽然客户端B的事务还没提交,但是客户端A就可以查询到B已经更新的数据。

    ## 查询id为1的数据
    select * from account where id = 1;
    

    在这里插入图片描述

  • 4、这里回滚客户端B的事务,一旦客户端B的事务因为某种原因回滚,所有的操作都将会被撤销,那客户端A查询到的数据其实就是脏数据。

    ## 回滚事务
    rollback;
    ## 查询id为1的数据
    select * from account where id = 1;
    

    在这里插入图片描述

  • 5、在客户端A给表account中id为1的数据添加50,id为1的balance还是1250,居然没有变成1300,数据和我们想要的是一致的这个操作好像没问题,如果你这么想就太天真了,在实际编写代码中,我们会先读取出客户端B修改后的数据1250,然后用1250+50=1300,最后会将这个1300更新到数据库中set balance = 1300,并不知道其他会话回滚了,当然我们可以也写成set balance = balance + 50 where id = 1这样数据是会有行锁的,最终更新数据时获取到的balance一定是已经提交后的数据,客户端B没有提交客户端A是会等待的,但是有些业务一定要写成set balance = 1300那就有问题了,要想解决这个问题可以采用读已提交的隔离级别。

    ## 给表account中id为1的数据添加50
    update account set balance = balance + 50 where id = 1;
    ## 查询id为1的数据
    select * from account where id = 1;
    ## 提交事务
    commit;
    

    在这里插入图片描述

7.2、读已提交(READ COMMITTED)案例分析

  • 1、打开一个客户端A,并设置当前session事务模式为读已提交(READ COMMITTED),查询表account的初始值。

    ## 设置当前session事务隔离级别为读已提交(READ COMMITTED)
    set session transaction isolation level READ COMMITTED;
    ## 开启事务
    begin;
    ## 查询表account的初始值
    select * from account;
    

    在这里插入图片描述

  • 2、在客户端A的事务提交之前,打开另一个客户端B并且也设置当前session事务模式为读已提交(READ COMMITTED),给表account中id为1的数据添加50。

    ## 设置当前session事务隔离级别为读已提交(READ COMMITTED)
    set session transaction isolation level READ COMMITTED;
    ## 开启事务
    begin;
    ## 给表account中id为1的数据添加50
    update account set balance = balance + 50 where id = 1;
    ## 查询id为1的数据
    select * from account where id = 1;
    

    在这里插入图片描述

  • 3、客户端A中查询表account中id为1的数据,客户端B的事务还没提交,所以查询不到数据修改,解决了脏读问题。

    ## 查询id为1的数据
    select * from account where id = 1;
    

    在这里插入图片描述

  • 4、提交客户端B的事务。

    ## 提交事务
    commit;
    

    在这里插入图片描述

  • 5、客户端A执行与上一步相同的查询,结果 与上一步不一致,即产生了不可重复读的问题。

    ## 查询id为1的数据
    select * from account where id = 1;
    

    在这里插入图片描述

  • 6、最后别忘记提交客户端A的事务了

    ## 提交事务
    commit;
    

7.3、可重复读(REPEATABLE READ)案例分析

  • 1、打开一个客户端A,并设置当前session事务模式为可重复读(REPEATABLE READ),查询表account的初始值。

    ## 设置当前session事务隔离级别为可重复读(REPEATABLE READ)
    set session transaction isolation level REPEATABLE READ;
    ## 开启事务
    begin;
    ## 查询表account的初始值
    select * from account;
    

    在这里插入图片描述

  • 2、在客户端A的事务提交之前,打开另一个客户端B并且也设置当前session事务模式为可重复读(REPEATABLE READ),给表account中id为1的数据添加50。

    ## 设置当前session事务隔离级别为可重复读(REPEATABLE READ)
    set session transaction isolation level REPEATABLE READ;
    ## 开启事务
    begin;
    ## 给表account中id为1的数据添加50
    update account set balance = balance + 50 where id = 1;
    ## 查询id为1的数据
    select * from account where id = 1;
    

    在这里插入图片描述

  • 3、客户端A中查询表account中id为1的数据,客户端B的事务还没提交,所以查询不到数据修改,解决了脏读问题。

    ## 查询id为1的数据
    select * from account where id = 1;
    

    在这里插入图片描述

  • 4、提交客户端B的事务。

    ## 提交事务
    commit;
    

    在这里插入图片描述

  • 5、客户端A执行与上一步相同的查询,结果 与上一步一致,解决了不可重复读的问题。

    ## 查询id为1的数据
    select * from account where id = 1;
    

    在这里插入图片描述

  • 6、在客户端A,接着执行给表account中id为1的数据添加50,balance变成了1350+50=1400,id为1的数据是按照客户端B提交的数据计算的而不是我们在客户端B查询出来的1300,所以是1400,数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC(multi-version concurrency control)机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。

    ## 给表account中id为1的数据添加50
    update account set balance = balance + 50 where id = 1;
    ## 查询id为1的数据
    select * from account where id = 1;
    

    在这里插入图片描述

  • 7、重新打开客户端B,插入一条新数据后提交

    ## 开始事务
    begin;
    ## 插入数据
    INSERT INTO `account`(`id`, `name`, `balance`) VALUES (4, 'Malia', 888);
    ## 查询全部数据
    select * from account;
    ## 提交事务
    commit;
    

    在这里插入图片描述

  • 8、在客户端A查询表account的所有记录,没有查出新增数据,所以没有出现幻读。

    ## 查询全部数据
    select * from account;
    

    在这里插入图片描述

  • 9、验证幻读在客户端A给 id 为 4的数据添加100,再次查询能查到客户端B新增的数据。

    ## 给表account中id为4的数据添加100
    update account set balance = balance + 100 where id = 4;
    ## 查询全部数据
    select * from account;
    

    在这里插入图片描述

  • 10、最后别忘记提交客户端A的事务了

    ## 提交事务
    commit;
    

7.4、串行化(SERIALIZABLE)案例分析

  • 1、打开一个客户端A,并设置当前session事务模式为串行化(SERIALIZABLE),查询表account的初始值。

    ## 设置当前session事务隔离级别为串行化(SERIALIZABLE)
    set session transaction isolation level SERIALIZABLE;
    ## 开启事务
    begin;
    ## 查询表account中id为1的行
    select * from account where id = 1;
    

    在这里插入图片描述

  • 2、打开一个客户端B,并设置当前事务模式为串行化(SERIALIZABLE),更新相同的id为1的记录会被阻塞等待,更新id为2的记录可以成功,说明在串行模式下innodb的查询也会被加上行锁,如果客户端A执行的是一个范围查询,那么该范围内的所有行包括每行记录所在的间隙区间范围(就算该行数据还未被插入也会加锁,这种是间隙锁)都会被加锁。此时如果客户端B在该范围内插入数据都会被阻塞,所以就避免了幻读,这种隔离级别并发性极低,开发中很少会用到。

    ## 设置当前session事务隔离级别为串行化(SERIALIZABLE)
    set session transaction isolation level READ SERIALIZABLE;
    ## 开启事务
    begin;
    ## 给表account中id为1的数据添加50
    update account set balance = balance + 50 where id = 1;
    ## 给表account中id为2的数据添加50
    update account set balance = balance + 50 where id = 2;
    ## 查询id为1的数据
    select * from account where id = 1;
    

    在这里插入图片描述

  • 3、最后别忘记提交客户端A的事务了

    ## 提交事务
    commit;
    

八、其它问题

8.1、无索引行锁会升级为表锁

      InnoDB存储引擎只有通过索引条件检索数据才使用行级锁,否则,InnoDB将使用表级锁;也就是说,InnoDB的行锁是基于索引的。

8.1.1、问题复现
  • 1、打开一个客户端A,通过没有索引的name字段更新数据,这里给name='Kerwin’的数据增加100。

    ## 设置当前session事务隔离级别为可重复读(REPEATABLE READ)
    set session transaction isolation level REPEATABLE READ;
    ## 开启事务
    begin;
    ## 给表account中name为Kerwin的数据添加100
    update account set balance = balance + 100 where `name` = 'Kerwin';
    

    在这里插入图片描述

  • 2、打开一个客户端B,给id为1的数据添加100,给id为2的数据添加100,这两个更新语句都会出现锁等待超时,代表客户端A通过没有索引的name字段更新数据出现了表锁。

    ## 设置当前session事务隔离级别为可重复读(REPEATABLE READ)
    set session transaction isolation level REPEATABLE READ;
    ## 给表account中id为1的数据添加100
    update account set balance = balance + 100 where id = 1;
    ## 给表account中id为2的数据添加100
    update account set balance = balance + 100 where id = 2;
    

    在这里插入图片描述

  • 3、最后别忘记提交客户端A的事务了

    ## 提交事务
    commit;
    
8.1.2、问题解决

解决问题有两个方向

  • 1、以先将数据id查询出来,然后通过id去更新 (推荐)
  • 2、或者添加对应字段索引

这里说说第二种添加索引来解决:

## 添加name字段索引
ALTER TABLE `account` ADD INDEX `idx_name`(`name`);

索引添加好在进行上面的测试,更新id为1的数据会被锁住,而更新id为2的数据不会在被锁。

8.2、死锁问题

这里以行锁来演示死锁问题。

8.2.1、死锁问题复现
  • 1、打开一个客户端A,开启事务先给id为1的数据添加100。

    ## 设置当前session事务隔离级别为可重复读(REPEATABLE READ)
    set session transaction isolation level REPEATABLE READ;
    ## 开启事务
    begin;
    ## 给表account中id为1的数据添加100
    update account set balance = balance + 100 where id = 1;
    

    在这里插入图片描述

  • 2、打开一个客户端B,开启事务先给id为2的数据添加100。

    ## 设置当前session事务隔离级别为可重复读(REPEATABLE READ)
    set session transaction isolation level REPEATABLE READ;
    ## 开启事务
    begin;
    ## 给表account中id为2的数据添加100
    update account set balance = balance + 100 where id = 2;
    

    在这里插入图片描述

  • 3、在客户端A中再给id为2的数据添加100,这里可以看到更新id为2的数据一直在等待,因为客户端B中事务也在更新id为2的数据。

    ## 给表account中id为2的数据添加100
    update account set balance = balance + 100 where id = 2;
    

    在这里插入图片描述

  • 4、在客户端B中再给id为1的数据添加100,这里可以看到在更新id为1的数据时出现了死锁,因为客户端A中事务持有id为1的锁,并且在等待客户端B中事务持有的id为2的锁,当客户端B想要更新id为1的数据就形成了一个环都在等待对方的锁从而出现了死锁,出现了死锁其中一个事务会失败回滚另外一个事务执行成功。

    ## 给表account中id为1的数据添加100
    update account set balance = balance + 100 where id = 1;
    

    在这里插入图片描述

8.2.2、问题解决

对于演示中出现的死锁问题很好解决,业务中避免这样写就行。

8.3、行锁分析

通过检查innodb_row_lock%状态变量来分析系统上的行锁的争夺情况。

show status like 'innodb_row_lock%';

对各个状态量的说明如下:

  • Innodb_row_lock_current_waits: 当前正在等待锁定的数量
  • Innodb_row_lock_time: 从系统启动到现在锁定总时间长度
  • Innodb_row_lock_time_avg: 每次等待所花平均时间
  • Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花时间
  • Innodb_row_lock_waits:系统启动后到现在总共等待的次数

8.4、查看锁和事务信息

#查询是否有锁表
show open tables where in_use > 0;

#查询被锁的表
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

#查询进程
show processlist;

#杀死进程
kill xx;

#查看正在进行的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
#查看正在锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
#查看等待锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

#杀死线程id(就是[select * from information_schema.INNODB_TRX; ]命令的trx_mysql_thread_id列)
kill 线程ID


#查看服务器状态
show status like '%lock%';

#查看超时时间
show variables like '%timeout%';

#查询事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

字段解析
innodb_trx表:
trx_id:事务ID。
trx_state:事务状态,有以下几种状态:RUNNING、LOCK WAIT、ROLLING BACK 和 COMMITTING。
trx_started:事务开始时间。
trx_requested_lock_id:事务当前正在等待锁的标识,可以和 INNODB_LOCKS 表 JOIN 以得到更多详细信息。
trx_wait_started:事务开始等待的时间。
trx_weight:事务的权重。
trx_mysql_thread_id:事务线程 ID,可以和 PROCESSLIST 表 JOIN。
trx_query:事务正在执行的 SQL 语句。
trx_operation_state:事务当前操作状态。
trx_tables_in_use:当前事务执行的 SQL 中使用的表的个数。
trx_tables_locked:当前执行 SQL 的行锁数量。
trx_lock_structs:事务保留的锁数量。
trx_lock_memory_bytes:事务锁住的内存大小,单位为 BYTES。
trx_rows_locked:事务锁住的记录数。包含标记为 DELETED,并且已经保存到磁盘但对事务不可见的行。
trx_rows_modified:事务更改的行数。
trx_concurrency_tickets:事务并发票数。
trx_isolation_level:当前事务的隔离级别。
trx_unique_checks:是否打开唯一性检查的标识。
trx_foreign_key_checks:是否打开外键检查的标识。
trx_last_foreign_key_error:最后一次的外键错误信息。
trx_adaptive_hash_latched:自适应散列索引是否被当前事务锁住的标识。
trx_adaptive_hash_timeout:是否立刻放弃为自适应散列索引搜索 LATCH 的标识。
 
#查看正在锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; 

lock_id:锁 ID。
lock_trx_id:拥有锁的事务 ID。可以和 INNODB_TRX 表 JOIN 得到事务的详细信息。
lock_mode:锁的模式。有如下锁类型:行级锁包括:S、X、IS、IX,分别代表:共享锁、排它锁、意向共享锁、意向排它锁。表级锁包括:S_GAP、X_GAP、IS_GAP、IX_GAP 和 AUTO_INC,分别代表共享间隙锁、排它间隙锁、意向共享间隙锁、意向排它间隙锁和自动递增锁。
lock_type:锁的类型。RECORD 代表行级锁,TABLE 代表表级锁。
lock_table:被锁定的或者包含锁定记录的表的名称。
lock_index:当 LOCK_TYPE=’RECORD’ 时,表示索引的名称;否则为 NULL。
lock_space:当 LOCK_TYPE=’RECORD’ 时,表示锁定行的表空间 ID;否则为 NULL。
lock_page:当 LOCK_TYPE=’RECORD’ 时,表示锁定行的页号;否则为 NULL。
lock_rec:当 LOCK_TYPE=’RECORD’ 时,表示一堆页面中锁定行的数量,亦即被锁定的记录号;否则为 NULL。
lock_data:当 LOCK_TYPE=’RECORD’ 时,表示锁定行的主键;否则为NULL#查看等待锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

requesting_trx_id:请求事务的 ID。
requested_lock_id:事务所等待的锁定的 ID。可以和 INNODB_LOCKS 表 JOIN。
blocking_trx_id:阻塞事务的 ID。
blocking_lock_id:某一事务的锁的 ID,该事务阻塞了另一事务的运行。可以和 INNODB_LOCKS 表 JOIN

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1061994.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网络安全 --- XSS漏洞利用实战】你知道如何利用XSS漏洞进行cookie获取,钓鱼以及键盘监听吗?--- XSS实战篇

一&#xff0c;XSS 实战 以pikachu靶场为例 1-1 盗取cookie 过程&#xff1a;想要盗取别人的cookie信息的话有一个前提条件&#xff0c;就是你应该在别人触发你的xss攻击时&#xff0c;你的代码应该将收集的cookie信息发送给你的平台来接收&#xff0c;这样才获取到了数据 …

图的广度遍历-邻接矩阵实现

description 本题要求实现邻接矩阵存储图的广度优先遍历。 函数接口定义&#xff1a; void BFS(MGraph G,Vertex i); 其中MGraph是邻接矩阵存储的图&#xff0c;定义如下&#xff1a; #define MaxVertexNum 10 /定义最大顶点数/ typedef int Vertex;/* 用顶点下标表示顶点,…

1799_GNU pdf阅读器evince_windows系统下编译尝试

全部学习汇总&#xff1a; GreyZhang/g_GNU: After some years I found that I do need some free air, so dive into GNU again! (github.com) 从网上下载下来了evince的代码&#xff0c;尝试做一个windows下的编译。 这应该是autotools的构建系统&#xff0c;先尝试运行confi…

java做个qq机器人

前置的条件 机器人是基于mirai框架实现的。根据官方的文档&#xff0c;建议使用openjdk11。 我这里使用的编辑工具是idea2023 在idea中新建一个maven项目&#xff0c;虽然可以使用gradle进行构建&#xff0c;不过我这里由于网络问题没有跑通。 pom.xml <dependency>&l…

提示msvcp140.dll丢失的5个解决方法,msvcp140.dll丢失问题全面分析

在我们的日常生活和工作中&#xff0c;电脑已经成为不可或缺的工具。然而&#xff0c;在使用电脑的过程中&#xff0c;我们经常会遇到各种问题&#xff0c;其中就包括提示 msvcp140.dll 丢失的问题。msvcp140.dll 是 Visual C Redistributable for Visual Studio 2015 的运行时…

堆--数组中第K大元素

如果对于堆不是太认识&#xff0c;请点击&#xff1a;堆的初步认识-CSDN博客 解题思路&#xff1a; /*** <h3>求数组中第 K 大的元素</h3>* <p>* 解体思路* <ol>* 1.向小顶堆放入前k个元素* 2.剩余元素* 若 < 堆顶元素, 则略过* …

SM5308 2.1A 充电 2.4 A 放电高集成度移动电源 SOC 可替代IP5306

SM5308 是一款集成升压转换器、锂电池充电管理、电池电量指示的多功能电源管理 SOC&#xff0c;为移动电源 提供完整的电源解决方案。 SM5308 的高集成度与丰富功能,使其在应用时仅需极少的外围器件,并有效减小整体方案的尺寸&#xff0c; 降低 BOM 成本。 SM5308 只需一个电…

竞赛选题 深度学习 opencv python 实现中国交通标志识别

文章目录 0 前言1 yolov5实现中国交通标志检测2.算法原理2.1 算法简介2.2网络架构2.3 关键代码 3 数据集处理3.1 VOC格式介绍3.2 将中国交通标志检测数据集CCTSDB数据转换成VOC数据格式3.3 手动标注数据集 4 模型训练5 实现效果5.1 视频效果 6 最后 0 前言 &#x1f525; 优质…

1797_GNU pdf阅读器evince

全部学习汇总&#xff1a; GreyZhang/g_GNU: After some years I found that I do need some free air, so dive into GNU again! (github.com) 近段时间经历了很多事情&#xff0c;终于想找一点技术上的自由气氛。或许&#xff0c;没有什么比GNU的一些软件探索更适合填充这样的…

千禧辣妹风穿搭必备——轻律U1头戴式耳机百搭不出错

千禧辣妹风的打造方法十分多样。我们可以在衣服造型多变&#xff0c;还可以在饰品上改造&#xff0c;从而打造出一种随性&#xff0c;辣妹炸眼的格调。特别是头戴式耳机很适合我们去塑造属于自己的千禧辣妹Y2K的美感&#xff0c;轻律umelody U1采用棕银配色&#xff0c;光是外观…

二叉树的遍历方式和代码

二叉树的三种遍历和代码 1.前序遍历2.中序遍历3.后序遍历4.三种遍历方式的代码实现 1.前序遍历 学习二叉树结构&#xff0c;最简单的方式就是遍历。所谓遍历(Traversal)是指沿着某条搜索路线&#xff0c;依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具…

如何使用 Bing Image Creator 创建图像(DALL-E3)

Bing Image Creator 是一个由微软开发的人工智能图像生成工具&#xff0c;可以根据用户的文字描述生成逼真的图像。该工具使用了 OpenAI 的 DALL-E 3 模型&#xff0c;可以生成各种各样的图像&#xff0c;包括人物、动物、场景、物体等。 使用 Bing Image Creator 创建图像 要…

VUE3照本宣科——路由与状态管理器

VUE3照本宣科——路由与状态管理器 前言一、路由&#xff08;router&#xff09;1.createRouter2.router-link3.router-view4.useRoute5.useRouter6.路由守卫7.嵌套路由 二、状态管理器&#xff08;Pinia&#xff09;1.定义Store&#xff08;1&#xff09;Option Store&#x…

用Python操作PPT的办公自动化教程

PPT通过其精美的可视化技巧以及良好的演示效果&#xff0c;成为了职场人士的必备技能。PPT的设计是一门大学问&#xff0c;无论是设计技巧&#xff0c;还是操作方法&#xff0c;都衍生出了专门的课程。 主要介绍Python操作PPT的技巧&#xff0c;编程的优势在于处理速度&#x…

李沐深度学习记录4:12.权重衰减/L2正则化

权重衰减从零开始实现 #高维线性回归 %matplotlib inline import torch from torch import nn from d2l import torch as d2l#整个流程是&#xff0c;1.生成标准数据集&#xff0c;包括训练数据和测试数据 # 2.定义线性模型训练 # 模型初始化&#xff08;函…

【docker】数据卷和数据卷容器

一、如何管理docker容器中的数据&#xff1f; 二、数据卷 1、数据卷原理 将容器内部的配置文件目录&#xff0c;挂载到宿主机指定目录下 数据卷默认会一直存在&#xff0c;即使容器被删除 宿主机和容器是两个不同的名称空间&#xff0c;如果想进行连接需要用ssh&#xff0c;…

联合概率和条件概率的区别和联系

联合概率P(A∩B) 两个事件一起&#xff08;或依次&#xff09;发生的概率。 例如&#xff1a;掷硬币的概率是 ⁄₂ 50%&#xff0c;翻转 2 个公平硬币的概率是 ⁄₂ ⁄₂ ⁄₄ 25%&#xff08;这也可以理解为 50% 的 50%&#xff09; 对于 2 个硬币&#xff0c;样本空间将…

开机可用内存分析Tip

一、开机内存简介 开机内存指的是开机一段时间稳定后的可用内存。一般项目都会挑选同平台其他优秀竞品内存数据&#xff0c;这个也是衡量性能的一个重要标准。所以要进行开机内存检测&#xff0c;同时优化非法内存进程占用。 二、测试前期核查任务 开机内存测试前要进行测试机…

十二、同步互斥与通信

1、概述 (1)可以把多任务系统当做一个团队&#xff0c;里面的每一个任务就相当于团队中的一个人。团队成员之间要协调工作进度(同步)、争用会议室(互斥)、沟通(通信)。多任务系统中所涉及的概念&#xff0c;都可以在现实生活中找到例子。 (2)各类RTOS都会涉及这些概念&#x…

C语言编程经典100例——11至20例

目录 第 11 例 第 12 例 第 13 例 第 14 例 第 15 例 第 16 例 第 17 例 第 18 例 第 19 例 第 20 例 第 11 例 程序源码&#xff1a; /* 题目&#xff1a;古典问题&#xff08;兔子生崽&#xff09;&#xff1a;有一对兔子&#xff0c;从出生后第3个月起每个月都生…