我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何理解MySQL 5.5 InnoDB表锁

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何理解MySQL 5.5 InnoDB表锁

本篇文章为大家展示了如何理解MySQL 5.5 InnoDB表锁,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

对于没有索引的表,MySQL会使用表级锁,写操作不会阻塞读操作,读操作不会阻塞写操作;一个会话的写操作会对整张表加锁,其他会话想修改表需要等到这个会话提交或回滚事务。

会话①
mysql> create table t12(id tinyint(3) unsigned not null,
    ->       name varchar(10) not null)
    ->       engine=innodb auto_increment=8 default charset=gbk;
Query OK, 0 rows affected (0.12 sec)

mysql> show keys from t12;
Empty set (0.00 sec)

mysql> show variables like '%commit%';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| autocommit                     | ON    |
| innodb_commit_concurrency      | 0     |
| innodb_flush_log_at_trx_commit | 1     |
+--------------------------------+-------+
3 rows in set (0.00 sec)

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%commit%';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| autocommit                     | OFF   |
| innodb_commit_concurrency      | 0     |
| innodb_flush_log_at_trx_commit | 1     |
+--------------------------------+-------+
3 rows in set (0.00 sec)

mysql> insert into t12 values(10,'Neo');
Query OK, 1 row affected (0.00 sec)

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

mysql> select * from t12;
+----+------+
| id | name |
+----+------+
| 10 | Neo  |
+----+------+
1 row in set (0.00 sec)

会话②
mysql> show variables like '%commit%';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| autocommit                     | ON    |
| innodb_commit_concurrency      | 0     |
| innodb_flush_log_at_trx_commit | 1     |
+--------------------------------+-------+
3 rows in set (0.00 sec)

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%commit%';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| autocommit                     | OFF   |
| innodb_commit_concurrency      | 0     |
| innodb_flush_log_at_trx_commit | 1     |
+--------------------------------+-------+
3 rows in set (0.00 sec)

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

mysql> select * from t12;
+----+------+
| id | name |
+----+------+
| 10 | Neo  |
+----+------+
1 row in set (0.00 sec)

会话①
mysql> update t12 set name='trinity' where id=10;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

会话②
下面DML语句会一直阻塞
mysql> insert into t12 values(20,'Trinity');

过一段时间会出现超时提示
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

会话①
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

会话②
mysql> insert into t12 values(20,'Trinity');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

对于有索引的表,写操作不会阻塞读操作,读操作不会阻塞写操作;如果在MySQL在写操作时使用索引扫描,则会使用行级锁,一个会话的写操作会对修改的行加锁,其他会话想修改这些行需要等到这个会话提交或回滚事务,其他会话对其他行的写操作不受影响,行锁会阻塞表锁;如果MySQL使用全表扫描,则会使用表级锁,一个会话的写操作会对整张表加锁,其他会话想修改表需要等到这个会话提交或回滚事务,表锁会阻塞行锁

会话①
mysql> create index idx_t12_id on t12(id);
Query OK, 0 rows affected (0.26 sec)
Records: 0  Duplicates: 0  Warnings: 0

查看索引
mysql> show keys from t12;
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| t12   |          1 | idx_t12_id |            1 | id          | A         |           3 |     NULL | NULL   |      | BTREE      |         |               |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

查看执行计划
mysql> explain select * from t12 where id=20;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | t12   | ALL  | idx_t12_id    | NULL | NULL    | NULL |    1 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

mysql> delete from t12 where id=20;
Query OK, 2 rows affected (0.00 sec)

mysql> select * from t12;
+----+------+
| id | name |
+----+------+
| 10 | Neo  |
+----+------+
1 row in set (0.00 sec)

会话②

查看执行计划
mysql> explain select * from t12 where id=10;
+----+-------------+-------+------+---------------+------------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key        | key_len | ref   | rows | Extra |
+----+-------------+-------+------+---------------+------------+---------+-------+------+-------+
|  1 | SIMPLE      | t12   | ref  | idx_t12_id    | idx_t12_id | 1       | const |    1 |       |
+----+-------------+-------+------+---------------+------------+---------+-------+------+-------+
1 row in set (0.00 sec)

mysql> update t12 set name='Jack' where id=10;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from t12;
+----+---------+
| id | name    |
+----+---------+
| 10 | Jack    |
| 20 | Trinity |
| 20 | Trinity |
+----+---------+
3 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.01 sec)

mysql> show processlist;
+----+-----------------+-----------+------+---------+--------+-----------------------------------------------------------------------------+------------------+
| Id | User            | Host      | db   | Command | Time   | State                                                                       | Info             |
+----+-----------------+-----------+------+---------+--------+-----------------------------------------------------------------------------+------------------+
|  1 | system user     |           | NULL | Connect | 769140 | Slave has read all relay log; waiting for the slave I/O thread to update it | NULL             |
|  2 | system user     |           | NULL | Connect | 769141 | Connecting to master                                                        | NULL             |
| 13 | event_scheduler | localhost | NULL | Daemon  | 621090 | Waiting on empty queue                                                      | NULL             |
| 76 | neo             | localhost | fire | Sleep   |    180 |                                                                             | NULL             |
| 78 | neo             | localhost | fire | Query   |      0 | NULL                                                                        | show processlist |
+----+-----------------+-----------+------+---------+--------+-----------------------------------------------------------------------------+------------------+
5 rows in set (0.00 sec)

mysql> explain select * from t12;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | t12   | ALL  | NULL          | NULL | NULL    | NULL |    1 |       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)

下面的更新没有使用索引而使用全表扫描,这样会加表级锁,会处于阻塞状态。
mysql> update t12 set name='Jack';
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

会话①

mysql> rollback;
Query OK, 0 rows affected (0.05 sec)

会话②
随着会话①的回滚操作,会话②执行成功
mysql> update t12 set name='Jack';
Query OK, 3 rows affected (12.41 sec)
Rows matched: 3  Changed: 3  Warnings: 0

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

会话①
mysql> update t12 set name='Jack';
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3  Changed: 3  Warnings: 0

会话②
插入操作会一直处于阻塞状态
mysql> insert into t12 values(30,'Lily');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

会话①
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

会话②
mysql> insert into t12 values(30,'Lily');
Query OK, 1 row affected (0.09 sec)

两行数据使用了同一个索引,对两个不同的行加锁,也会引起锁等待
mysql> show create table tab_with_index\G
*************************** 1. row ***************************
       Table: tab_with_index
Create Table: CREATE TABLE `tab_with_index` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(10) DEFAULT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> select * from tab_with_index where id=1;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
|    1 | 4    |
+------+------+
2 rows in set (0.00 sec)

mysql> show keys from tab_with_index;
+----------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table          | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| tab_with_index |          1 | id       |            1 | id          | A         |           7 |     NULL | NULL   | YES  | BTREE      |         |               |
+----------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

会话①
使用where id=1 and name='1'条件进行查询
mysql> select * from tab_with_index where id=1 and name='1' for update;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
+------+------+
1 row in set (0.00 sec)

会话②
查询where id=1 and name='4'条件进行查询,由于和会话①使用了相同的索引,即使查询了不同的字段,也会引起锁等待
mysql> select * from tab_with_index where id=1 and name='4' for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

在这种情况下,可以考虑创建联合索引
会话①
mysql> create index idx_id_name on tab_with_index(id,name);
Query OK, 0 rows affected (0.24 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from tab_with_index where id=1 and name='4' for update;
+------+------+
| id   | name |
+------+------+
|    1 | 4    |
+------+------+
1 row in set (0.00 sec)

会话②
mysql> select * from tab_with_index where id=1 and name='1' for update;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
+------+------+
1 row in set (0.00 sec)

InnoDB存储引擎的表使用不同索引的阻塞例子

会话①
mysql> show create table tab_with_index\G
*************************** 1. row ***************************
       Table: tab_with_index
Create Table: CREATE TABLE `tab_with_index` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(10) DEFAULT NULL,
  KEY `id` (`id`),
  KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> desc tab_with_index;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  | MUL | NULL    |       |
| name  | varchar(10) | YES  | MUL | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> select * from tab_with_index;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
|    2 | 2    |
|    3 | 3    |
|    4 | 4    |
|    1 | 4    |
+------+------+
5 rows in set (0.00 sec)

mysql> explain select * from tab_with_index where id=1 for update;
+----+-------------+----------------+------+---------------+------+---------+-------+------+-------+
| id | select_type | table          | type | possible_keys | key  | key_len | ref   | rows | Extra |
+----+-------------+----------------+------+---------------+------+---------+-------+------+-------+
|  1 | SIMPLE      | tab_with_index | ref  | id            | id   | 5       | const |    2 | NULL  |
+----+-------------+----------------+------+---------------+------+---------+-------+------+-------+
1 row in set (0.00 sec)

mysql> select * from tab_with_index where id=1;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
|    1 | 4    |
+------+------+
2 rows in set (0.00 sec)

mysql> select * from tab_with_index where id=1 for update;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
|    1 | 4    |
+------+------+
2 rows in set (0.01 sec)

会话②
mysql> explain select * from tab_with_index where name='4' for update;
+----+-------------+----------------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table          | type | possible_keys | key      | key_len | ref   | rows | Extra                 |
+----+-------------+----------------+------+---------------+----------+---------+-------+------+-----------------------+
|  1 | SIMPLE      | tab_with_index | ref  | idx_name      | idx_name | 13      | const |    2 | Using index condition |
+----+-------------+----------------+------+---------------+----------+---------+-------+------+-----------------------+
1 row in set (0.00 sec)

mysql> select * from tab_with_index where name='4' for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

上述内容就是如何理解MySQL 5.5 InnoDB表锁,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注亿速云行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何理解MySQL 5.5 InnoDB表锁

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

mysql锁官方文档与理解之InnoDB锁

This section describes lock types used by InnoDB.翻译:本节描述了InnoDB使用的锁类型。Shared and Exclusive Locks(共享锁和排他锁)Intention Locks(意向锁)Recor
mysql锁官方文档与理解之InnoDB锁
2021-05-07

MySQL InnoDB锁类型及锁原理实例解析

目录锁共享锁排他锁意向锁记录锁间隙锁临键锁死锁死锁产生条件行锁发生死锁表锁发生死锁锁的释放事务阻塞死锁的避免锁的日志行锁的原理不带任何索引的表带主键索引的表带唯一索引的表结论1.表必定有索引2.唯一索引数据行加锁,主键索引同样被锁锁锁是用
2022-11-27

mysql表锁住了如何解锁

要解锁MySQL表,可以使用以下方法之一:执行COMMIT或ROLLBACK语句:如果当前会话持有了表锁,可以通过执行COMMIT或ROLLBACK语句来释放锁定。重启MySQL服务:如果表锁定是由于其他会话中出现了意外的锁定请求而导致的,
2023-10-24

mysql表被锁了如何处理

当MySQL表被锁定时,可以尝试以下方法来处理:查看当前锁定表的情况:可以使用SHOW OPEN TABLES命令来查看当前表的锁定情况。检查是否有其他会话正在锁定该表:使用SHOW FULL PROCESSLIST命令查看当前MySQL服
mysql表被锁了如何处理
2024-04-09

mysql加字段锁表如何解决

在MySQL中,可以使用ALTER TABLE语句添加字段,但这会锁定整个表,导致其他用户无法访问或修改表。为了解决这个问题,可以使用以下方法:在非高峰时段进行添加字段操作,以减少对其他用户的影响。在添加字段之前,先备份表数据,以防意外情
mysql加字段锁表如何解决
2024-04-09

PLsql锁表后如何解锁

PL/SQL中并没有专门的锁表和解锁表的语句,通常是通过使用数据库管理系统提供的锁定机制来锁定和解锁表。在Oracle数据库中,可以使用以下语句来锁定表:LOCK TABLE table_name IN EXCLUSIVE MODE;要
PLsql锁表后如何解锁
2024-04-09

mysql如何使用表锁

这篇文章给大家分享的是有关mysql如何使用表锁的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1、全表更新。事务需要更新大部分或全部数据,且表又比较大。若使用行锁,会导致事务执行效率低,从而可能造成其他事务长时间
2023-06-15

如何理解InnoDB引擎

这期内容当中小编将会给大家带来有关如何理解InnoDB引擎,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、综述innodb的物理文件包括系统表空间文件ibdata,用户表空间文件ibd,日志文件ib_l
2023-05-31

编程热搜

目录