一、序言

上一篇讲了下innodb中锁的大约含意, 这篇说说如何查看加的什么锁。要不然事后发生死锁或是锁等候都不清楚为何。

二、最底层基本表信息内容

在学好怎么查看有什么锁信息内容时, 必须掌握一些基本表信息内容, 这种能帮助我们迅速清查。

过去几篇文章内容能够 掌握到innodb中的锁是在事务管理内实行的,因此 大家先掌握下最底层的事务管理表看一下从这当中能够 看得出什么內容。

2.1 information_schema.INNODB_TRX

最底层有两个databases

mysql> show databases;
 -------------------- 
| Database           |
 -------------------- 
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test_db            |
 -------------------- 
5 rows in set (0.01 sec)

能够 挑选information_schema 查询下边是不是有事务管理有关的表。

mysql> use information_schema;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables like '%tr%';
 ------------------------------------- 
| Tables_in_information_schema (%TR%) |
 ------------------------------------- 
| CHECK_CONSTRAINTS                   |
| INNODB_METRICS                      |
| INNODB_TRX                          |
| OPTIMIZER_TRACE                     |
| REFERENTIAL_CONSTRAINTS             |
| ST_GEOMETRY_COLUMNS                 |
| TABLE_CONSTRAINTS                   |
| TRIGGERS                            |
 ------------------------------------- 
8 rows in set (0.00 sec)

由此可见存有事务管理表INNODB_TRX, 随后看一下其表结构,随后对于每一个字段名的表述加上

mysql> show create table INNODB_TRX;
....

 INNODB_TRX | CREATE TEMPORARY TABLE `INNODB_TRX` (
   # 事务管理ID
  `trx_id` varchar(18) NOT NULL DEFAULT '',  
  # 事务管理情况, 规定值是 RUNNING,LOCK WAIT, ROLLING BACK,和 COMMITTING。
  `trx_state` varchar(13) NOT NULL DEFAULT '', 
  # 事务管理开始时间
  `trx_started` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  # 事务管理当今等候的锁的ID,假如TRX_STATE是LOCK WAIT;不然NULL。
  `trx_requested_lock_id` varchar(105) DEFAULT NULL, 
   # 事务管理逐渐等候锁的時间
  `trx_wait_started` datetime DEFAULT NULL,
  # 事务管理权重值, 体现(但不一定是精确记数)变更的个数和事务管理锁住的个数。为了更好地处理死锁, InnoDB挑选权重值最少的事务管理做为“受害人”开展回退。不管变更和锁住行的总数怎样,变更非事务管理表的事务管理都被觉得比别的事务管理更重。
  `trx_weight` bigint(21) unsigned NOT NULL DEFAULT '0', 
  # MySQL 进程 ID。 这一id很重要,假如发觉某一事务管理一直等待没法完毕得话,能够 根据这一ID kill掉。
  `trx_mysql_thread_id` bigint(21) unsigned NOT NULL DEFAULT '0', 
  # 事务管理已经实行的 SQL 句子。
  `trx_query` varchar(1024) DEFAULT NULL,
  # 买卖的当今实际操作,如果有得话;不然 NULL。
  `trx_operation_state` varchar(64) DEFAULT NULL,
  # InnoDB解决此事务管理的当今 SQL 句子时应用 的表数。
  `trx_tables_in_use` bigint(21) unsigned NOT NULL DEFAULT '0',
  # InnoDB当今 SQL 句子具备行锁 的表数。(由于这种是行锁,而不是表锁,虽然一些行被锁住,但一般仍能够 由好几个事务管理载入和载入表。)
  `trx_tables_locked` bigint(21) unsigned NOT NULL DEFAULT '0',
  # 事务管理保存的锁数。
  `trx_lock_structs` bigint(21) unsigned NOT NULL DEFAULT '0',
  # 此事务管理的锁构造在运行内存中占有的总尺寸。
  `trx_lock_memory_bytes` bigint(21) unsigned NOT NULL DEFAULT '0',
  # 此事务管理锁住的大概总数或个数。该值很有可能包含物理学上存有但对事务管理不由此可见的删掉标识行。
  `trx_rows_locked` bigint(21) unsigned NOT NULL DEFAULT '0',
  # 此事务管理中改动和插进的个数。
  `trx_rows_modified` bigint(21) unsigned NOT NULL DEFAULT '0',
  `trx_concurrency_tickets` bigint(21) unsigned NOT NULL DEFAULT '0',
  # 当今事务管理的隔离级别。
  `trx_isolation_level` varchar(16) NOT NULL DEFAULT '',
  `trx_unique_checks` int(1) NOT NULL DEFAULT '0',
  `trx_foreign_key_checks` int(1) NOT NULL DEFAULT '0',
  `trx_last_foreign_key_error` varchar(256) DEFAULT NULL,
  `trx_adaptive_hash_latched` int(1) NOT NULL DEFAULT '0',
  `trx_adaptive_hash_timeout` bigint(21) unsigned NOT NULL DEFAULT '0',
  `trx_is_read_only` int(1) NOT NULL DEFAULT '0',
  `trx_autocommit_non_locking` int(1) NOT NULL DEFAULT '0'
) ENGINE=MEMORY DEFAULT CHARSET=utf8 |

1 row in set (0.00 sec)

以上早已对于关键字段名开展了注解表明,该表主要是纪录事务管理中的一些信息内容,十分有效,在其中便会纪录等钱等候锁的ID。

详尽可以看官方网文本文档:https://dev.mysql.com/doc/refman/8.0/en/information-schema-innodb-trx-table.html

在其中下列几个字段必须尤其注意下,

TRX_ID                  事务管理ID, 
TRX_REQUESTED_LOCK_ID   事务管理当今等候的锁的ID。 假如当今事务管理堵塞就可以看得出以前的锁
TRX_MYSQL_THREAD_ID     MySQL 进程 ID

2.2 performance_schema.data_locks

以上事务管理表格中有纪录当今等候锁的ID, 那麼这一id来源于哪儿呢?
能够 在information_schema performance_schema中检索show tables like '%lock%';, 后边发觉在performance_schema

mysql> show tables like '%lock%';
 --------------------------------------- 
| Tables_in_performance_schema (%lock%) |
 --------------------------------------- 
| data_lock_waits                       |
| data_locks                            |
| metadata_locks                        |
| rwlock_instances                      |
| table_lock_waits_summary_by_table     |
 --------------------------------------- 
5 rows in set (0.00 sec)

先看一下data_locks的表构造:

CREATE TABLE `data_locks` (
  # 拥有或要求锁的储存模块。
  `ENGINE` varchar(32) NOT NULL,
  # 储存模块拥有或要求的锁的 ID。( ENGINE_LOCK_ID, ENGINE) 值的元组是唯一的。
  # information_schema.INNODB_TRX.trx_requested_lock_id 就来自这
  `ENGINE_LOCK_ID` varchar(128) NOT NULL,
  # 要求锁住的事务管理的储存模块內部 ID 
  # 来源于information_schema.INNODB_TRX.TRX_ID
  `ENGINE_TRANSACTION_ID` bigint(20) unsigned DEFAULT NULL,
  # 建立锁的对话的进程 ID
  `THREAD_ID` bigint(20) unsigned DEFAULT NULL,
  `EVENT_ID` bigint(20) unsigned DEFAULT NULL,
  `OBJECT_SCHEMA` varchar(64) DEFAULT NULL,
  `OBJECT_NAME` varchar(64) DEFAULT NULL,
  `PARTITION_NAME` varchar(64) DEFAULT NULL,
  `SUBPARTITION_NAME` varchar(64) DEFAULT NULL,
  # 锁住数据库索引的名字
  `INDEX_NAME` varchar(64) DEFAULT NULL,
  `OBJECT_INSTANCE_BEGIN` bigint(20) unsigned NOT NULL,
  # 锁的种类。该值在于储存模块。针对 InnoDB,容许的数值 RECORD行级锁和 TABLE表级锁。
  `LOCK_TYPE` varchar(32) NOT NULL,
  # 怎样要求锁住。
  # 该值在于储存模块。为 InnoDB,规定值是 S[,GAP],X[,GAP], IS[,GAP],IX[,GAP], AUTO_INC,和 UNKNOWN。AUTO_INC和UNKNOWN 标示空隙锁住之外的锁住方式 (假如存有)
  `LOCK_MODE` varchar(32) NOT NULL,
  # 锁住要求的情况。
  # 该值在于储存模块。针对 InnoDB,容许的数值 GRANTED(锁住已拥有)和 WAITING(已经等候锁住)。
  `LOCK_STATUS` varchar(32) NOT NULL,
  `LOCK_DATA` varchar(8192) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  PRIMARY KEY (`ENGINE_LOCK_ID`,`ENGINE`),
  KEY `ENGINE_TRANSACTION_ID` (`ENGINE_TRANSACTION_ID`,`ENGINE`),
  KEY `THREAD_ID` (`THREAD_ID`,`EVENT_ID`),
  KEY `OBJECT_SCHEMA` (`OBJECT_SCHEMA`,`OBJECT_NAME`,`PARTITION_NAME`,`SUBPARTITION_NAME`)
) ENGINE=PERFORMANCE_SCHEMA DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

详尽主要参数表述请参照: https://dev.mysql.com/doc/refman/8.0/en/performance-schema-data-locks-table.html

从上边能够 了解当今事务管理假如拥有锁的就看得出它拥有的哪些种类的锁、锁情况。

三、实践活动得真谛

1、逐渐一个事务管理1, 对某条纪录加排他锁:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t where id = 3 for update;
 ---- ------ 
| id | name |
 ---- ------ 
|  3 | 3    |
 ---- ------ 
1 row in set (0.00 sec)

随后依据当今进程id查询事务管理信息内容:

mysql> select * from information_schema.INNODB_TRX where TRX_MYSQL_THREAD_ID = CONNECTION_ID() \G
*************************** 1. row ***************************
                    trx_id: 38441
                 trx_state: RUNNING
               trx_started: 2021-08-22 09:26:56
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 2
       trx_mysql_thread_id: 32
                 trx_query: select * from information_schema.INNODB_TRX where TRX_MYSQL_THREAD_ID = CONNECTION_ID()
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 1136
           trx_rows_locked: 1
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
1 row in set (0.00 sec)

能够 看得出当今事务管理ID38441, 锁住个数为1行, 合乎预估。

随后再依据事务管理ID查询锁信息内容:

mysql> select * from performance_schema.data_locks where ENGINE_TRANSACTION_ID = 38441 \G
*************************** 1. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 4720840032:1068:140354321295272
ENGINE_TRANSACTION_ID: 38441
            THREAD_ID: 72
             EVENT_ID: 246
        OBJECT_SCHEMA: test_db
          OBJECT_NAME: t
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140354321295272
            LOCK_TYPE: TABLE
            LOCK_MODE: IX
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
*************************** 2. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 4720840032:11:4:2:140354330466328
ENGINE_TRANSACTION_ID: 38441
            THREAD_ID: 72
             EVENT_ID: 246
        OBJECT_SCHEMA: test_db
          OBJECT_NAME: t
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140354330466328
            LOCK_TYPE: RECORD
            LOCK_MODE: X,REC_NOT_GAP
          LOCK_STATUS: GRANTED
            LOCK_DATA: 3
2 rows in set (0.00 sec)

能够 看得出当今事务管理相匹配2个锁信息内容, 第一个是表锁:意愿排他锁, 第二个是行锁:排他锁 且 非空隙锁, 全是拥有锁的情况, 并且锁的纪录也是primarKey = 3的那一条纪录。 合乎预估。

这儿很有可能会出现好奇心,为什么会出现表锁呢? 不了解的能够 再看一下以前的文章内容:https://www.cnblogs.com/yuanfy008/p/14993366.html

2、逐渐一个事务管理2, 先查询当今进程id, 随后对id=3的那一条纪录加排他锁。

mysql> begin;
mysql> select connection_id();
 ----------------- 
| connection_id() |
 ----------------- 
|              33 |
 ----------------- 
1 row in set (0.00 sec)

mysql> select * from t where id = 3 for update;

这也是会锁等候, 由于事务管理1占据着呢。

随后再去此外一个对话框依据mysql线程id查询事务管理状况:

mysql> select * from information_schema.INNODB_TRX where TRX_MYSQL_THREAD_ID = 33 \G
*************************** 1. row ***************************
                    trx_id: 38445
                 trx_state: LOCK WAIT
               trx_started: 2021-08-22 09:52:40
     trx_requested_lock_id: 4720840880:11:4:2:140354330471280
          trx_wait_started: 2021-08-22 09:55:56
                trx_weight: 2
       trx_mysql_thread_id: 33
                 trx_query: select * from t where id = 3 for update
       trx_operation_state: starting index read
         trx_tables_in_use: 1
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 1136
           trx_rows_locked: 2
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
1 row in set (0.00 sec)

能够 看得出当今事务管理还等待另一个锁(ID:4720840880:11:4:2:140354330471280)的释放出来,而这一锁的拥有这恰好是事务管理1。合乎预估

这个时候大家再去看看这一事务管理相匹配锁的信息内容, 那这个时候有两把锁呢? 应当仅有一把:表锁 - 意愿排他锁

mysql> select * from performance_schema.data_locks where ENGINE_TRANSACTION_ID = 38445 \G
*************************** 1. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 4720840880:1068:140354321297272
ENGINE_TRANSACTION_ID: 38445
            THREAD_ID: 73
             EVENT_ID: 31
        OBJECT_SCHEMA: test_db
          OBJECT_NAME: t
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140354321297272
            LOCK_TYPE: TABLE
            LOCK_MODE: IX
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
1 row in set (0.00 sec)
这就是本应努力的年龄,却想得过多,做得太少!

评论(0条)

刀客源码 游客评论