MySQL锁 、行锁、表锁、间隙锁、临键锁、共享锁、排它锁、意向锁
文章目录
- @[toc]
- 行锁
- 记录锁(Record Lock)
- 间隙锁(Gap Locks)
- 产生间隙锁的条件
- 间隙锁设置
- 间隙锁区间范围
- 测试
- 临键锁(Next-key Locks)
- 表锁
- 表锁 的读锁(共享锁)
- 表锁的写锁(排他锁)
- 页锁
- Innodb意向锁
- 定义
- 意向共享锁(Intent Share Lock,简称 IS 锁)
- 意向排它锁(Intent Exclusive Lock,简称 IX 锁)
- MySQL死锁
- 等待,直到超时
- 发起死锁检测
- 如何预防死锁
行锁
使用行锁是,如果匹配条件字段不带有索引时,Innodb会使用表锁;
行锁的 共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
行锁的 排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE
共享锁 可以理解为 读锁,拍他锁 理解为 写锁;
写锁不能和其他写锁 或者 读锁兼容,但是读锁可以和其他读锁兼容;
记录锁(Record Lock)
对主键或者唯一索引进行增删改或显示的加锁,InnoDB会加记录锁
## 显示的加锁,ID是主键 或 唯一索引
select * from people where id =3 for update;
间隙锁(Gap Locks)
间隙锁:锁加在不存在的空闲空间;
https://zhuanlan.zhihu.com/p/48269420
产生间隙锁的条件
产生间隙锁的条件(RR事务隔离级别下):
1. 使用普通索引锁定;
2. 使用 多列 唯一索引;
3. 使用唯一索引锁定 多行 记录。
如果,搜索条件里有多个查询条件(即使每个列都有唯一索引),也是会有间隙锁的。
间隙锁设置
查看间隙锁是否禁用
show variables like 'innodb_locks_unsafe_for_binlog';
默认值为OFF,即启用间隙锁;
关闭间隙锁
# 在 my.cnf 里面的[mysqld]添加
[mysqld]
innodb_locks_unsafe_for_binlog = 1
间隙锁区间范围
左开 右闭
测试
环境:MySQL,InnoDB,默认的隔离级别(RR)
数据表
CREATE TABLE `test` (`id` int(1) NOT NULL AUTO_INCREMENT,`name` varchar(8) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
数据
INSERT INTO `test` VALUES ('1', '小罗');
INSERT INTO `test` VALUES ('5', '小黄');
INSERT INTO `test` VALUES ('7', '小明');
INSERT INTO `test` VALUES ('11', '小红');
目前该表存在的间隙
(-infinity, 1]
(1, 5]
(5, 7]
(7, 11]
(11, +infinity]
测试
- 测试行锁
由于id是主键,因此这里加的是 行锁;
如果ID是普通索引,则下面的sql加的是(1,5]和(5,7]的间隙锁;
/* 开启事务1 */
BEGIN;
/*由于id是主键,因此这里加的是 行锁;*/
SELECT * FROM `test` WHERE `id` = 5 FOR UPDATE;
/* 延迟30秒执行,防止锁释放 */
SELECT SLEEP(30);
/* 提交事务1,释放事务1的锁 */
COMMIT;
在其他事物里插入id=4和id=6的数据 均能成功
INSERT INTO `test` (`id`, `name`) VALUES (4, '小张'); # 正常执行/* 事务3插入一条 name = '小张' 的数据 */
INSERT INTO `test` (`id`, `name`) VALUES (6, '小东'); # 正常执行
- 测试间隙锁
对主键 或 唯一索引加 范围 也可以开启 间隙锁;
/* 开启事务1 */
BEGIN;
/* 查询 id 在 7 - 11 范围的数据并加记录锁 */
SELECT * FROM `test` WHERE `id` BETWEEN 5 AND 7 FOR UPDATE;
/* 延迟30秒执行,防止锁释放 */
SELECT SLEEP(30);
/* 提交事务1,释放事务1的锁 */
COMMIT;
对区间(5,7] 和 (7-11]加间隙锁间隙锁;
/* 事务3插入一条 id = 4,name = '小白' 的数据 */
INSERT INTO `test` (`id`, `name`) VALUES (4, '小白'); # 正常执行/* 事务4插入一条 id = 6,name = '小东' 的数据 */
INSERT INTO `test` (`id`, `name`) VALUES (6, '小东'); # 阻塞/* 事务5插入一条 id = 8, name = '大罗' 的数据 */
INSERT INTO `test` (`id`, `name`) VALUES (8, '大罗'); # 阻塞/* 事务7插入一条 id = 11, name = '李西' 的数据 */
INSERT INTO `test` (`id`, `name`) VALUES (11, '李西'); # 阻塞/* 事务8插入一条 id = 12, name = '张三' 的数据 */
INSERT INTO `test` (`id`, `name`) VALUES (12, '张三'); # 正常执行
临键锁(Next-key Locks)
临键锁 也是一种 间隙锁;
例如表t1中有age作为普通索引;
其中存在的间隙为
(-∞,8]
(8,10]
(10,30]
(30,+∞]
那么
select * from t1 where age=10,则是对区间(8,10]
和(10,30]加锁,因为都是相邻age=10的区间,所以称为临键锁;
表锁
表级锁为表级别的锁定,会锁定整张表,可以很好的避免死锁
https://www.cnblogs.com/null-qige/p/8664009.html
用Lock Table来创建,在操作结束后,使用UnLock来释放锁。
表锁 的读锁(共享锁)
加锁 lock 表名 read;
解锁 unlock tables;
测试
创建了1个数据库locktest 和 2个表test_product 和 test_user;同时开启2个mysql client A、B;
A 客户端mysql> LOCK TABLES test_product READ;
Query OK, 0 rows affected (0.00 sec)mysql> select * from test_user-> ;
ERROR 1100 (HY000): Table 'test_user' was not locked with LOCK TABLES
a线程中对test_product加lock … read,但没有对test_user加锁,此时不允许对其他表进行访问;
在B中输入mysql> SELECT * FROM test_product limit 0,1;
+----+------+------+--------+----------+
| id | code | name | price | quantity |
+----+------+------+--------+----------+
| 1 | S001 | 1 | 100.00 | 200 |
+----+------+------+--------+----------+
1 row in set (0.00 sec)mysql> update test_product set price=250 where id=2;当更新操作时,一直卡在这里,等待a线程释放锁;
释放a线程的锁
a线程中输入
UNLOCK TABLES
b线程中mysql> update test_product set price=250 where id=2;
Query OK, 0 rows affected (2 min 11.63 sec)
Rows matched: 1 Changed: 0 Warnings: 0
a线程释放锁后,b线程成功修改了数据;
表锁的写锁(排他锁)
a线程中mysql> LOCK TABLES test_product WRITE;
Query OK, 0 rows affected (0.00 sec)mysql> select * from test_user;
ERROR 1100 (HY000): Table 'test_user' was not locked with LOCK TABLES
同理。加锁后不允许对 未加锁的表进行访问;
b线程中mysql> SELECT * FROM test_product limit 0,1;查询操作会一直卡在这里;
当在a线程中释放锁后,b线程便查询出了结果;
综上
Lock Tables…READ不会阻塞其他线程对表数据的读取,会阻塞其他线程对数据变更(增、删、改),并且不允许访问未被锁住的表;Lock Tables…WRITE会阻塞其他线程对数据的 读和写(增删改查),并且不允许访问未被锁住的表;
页锁
✌页锁运用在 BDB引擎,颗粒度和性能都位于 表锁和行所之间,会出现死锁;
Innodb意向锁
https://blog.csdn.net/dreamvyps/article/details/84500543
https://blog.csdn.net/yabingshi_tech/article/details/30495065
定义
意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;
对任一结点加锁时,必须先对它的上层结点加意向锁。如:对表中的任一行加锁时,必须先对它所在的表加意向锁,然后再对该行加锁。
事务a在T表的r行已经加了锁,事务b想对T表加 表锁,在没有意向锁的情况下,事务b需要遍历整个表才能知道有行锁,然后被阻塞,效率低;
意向锁分为 意向共享锁 和 意向排它锁;
意向共享锁(Intent Share Lock,简称 IS 锁)
如果要对一个数据库对象加S锁,首先要对其上级结点加IS 锁,表示它的后裔结点拟(意向)加 S锁;
意向排它锁(Intent Exclusive Lock,简称 IX 锁)
如果要对一个数据库对象加X 锁,首先要对其上级结点加 IX锁,表示它的后裔结点拟(意向)加X 锁。
MySQL死锁
表锁不会出现死锁,行锁、页锁可能出现死锁;
所谓死锁: 是指两个或两个以上的进程在执行过程中,
因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.
MySQL有两种死锁处理方式
等待,直到超时
- 事物1已经获得a表的锁,准备获取b表的锁,事物2已经获得b表的锁,正准备获取a表的锁,此时将发生死锁;
当一方的事物等待一段时间后就会自动放弃并回滚,innodb中通过innodb_lock_wait_timeout参数设置等待时间;
行锁会产生死锁,因为在行锁中,锁是逐步获得的,主要分为两步:锁住主键索引,锁住非主键索引。如:当两个事务同时执行时,一个锁住了主键索引,在等待其他索引;另一个锁住了非主键索引,在等待主键索引。这样便会发生死锁。InnoDB一般都可以检测到这种死锁,并使一个事务释放锁回退,另一个获取锁完成事务。
发起死锁检测
如何预防死锁
- 当对多个行(页)加锁时,保持加锁顺序一致;
- 同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
MySQL锁 、行锁、表锁、间隙锁、临键锁、共享锁、排它锁、意向锁相关推荐
- 5.15 mysql 数据库(数据库/表操作/索引/pymysql/备份与恢复/事务/锁) 学习笔记
文章目录 1 初始数据库 1)数据库 2)mysql 3)和用户权限相关的 4)基本操作 2 表操作 1)存储引擎 2)表和数据的一些基本操作 3)mysql中的数据类型 4)表的完整性约束 5)修改 ...
- 【Linux】mysql命令行查看表结构,字段等信息
mysql查看表结构命令,如下: desc table_name; //查表的字段信息(不包含字段内容) show columns from table_name; //同上 show create ...
- mysql命令行查看表的触发器_Mysql事项,视图,函数,触发器命令(详解)
事项开启和使用 //修改表的引擎 alter table a engine=myisam; //开启事务 begin; //关闭自动提交 set autocommit=0; //扣100 update ...
- mysql+字段+删除数据库表,MySQL命令行删除表中的一个字段
先看看删除之前的表结构: mysql> select * from test; +------+--------+----------------------------------+----- ...
- mysql 创建时间 只能设置一个_在MySQL中创建数据表时,可以设定主键、外键。那么对于一个数据表,能设置的主键和外键个数最多分别是...
关于面向对象概念的描述不正确的是( ). 关于面向对象概念的描述不正确的是( ). 嫌光性种子在光照下不能萌发. 下列项目不属于流动资产的是(). 采用螺纹联接时,若被联接件之-厚度较大,且材料较软, ...
- mysql innodb 全表锁,Mysql InnoDB行锁及表锁分享
一. 背景知识 二. 步入正题:表锁和行锁 1.1. 表锁 vs 行锁 在 MySQL 中锁的种类有很多,但是最基本的还是表锁和行锁:表锁指的是对一整张表加锁,一般是 DDL 处理时使用,也可以自己在 ...
- mysql临键锁_详解 MySql InnoDB 中的三种行锁(记录锁、间隙锁与临键锁)
详解 MySql InnoDB 中的三种行锁(记录锁.间隙锁与临键锁) 前言 InnoDB 通过 MVCC 和 NEXT-KEY Locks,解决了在可重复读的事务隔离级别下出现幻读的问题.MVCC ...
- mysql主键查询gap锁失效,mysql记录锁(record lock),间隙锁(gap lock),Next-key锁(Next-key lock)...
1. 什么是幻读? 幻读是在可重复读的事务隔离级别下会出现的一种问题,简单来说,可重复读保证了当前事务不会读取到其他事务已提交的 UPDATE 操作.但同时,也会导致当前事务无法感知到来自其他事务中的 ...
- MySQL之锁-行级锁
文章目录 MySQL之锁 1.行级锁分类 2.行锁(Record Locks) 2.1概念 2.2分类.兼容互斥情况 2.3查看意向锁与行锁 2.4操作讲解(共享锁与共享锁兼容) 2.5操作讲解(共享 ...
- mysql记录锁(record lock),间隙锁(gap lock),Next-key锁(Next-key lock)亲测
行锁 记录锁(record lock) 这是一个索引记录锁,它是建立在索引记录上的锁(主键和唯一索引都算),很多时候,锁定一条数据,由于无索引,往往会导致整个表被锁住,建立合适的索引可以防止扫描整个表 ...
最新文章
- Bicolor软件 中 GATB
- golang 得到 结构体 struct 标签 tag 内容 结构体中的``数据
- esp32 python-在esp32上配置运行microPython
- tfs文件系统之NS配置管理
- 使用jQuery来实现一个简单的ajax请求
- centos7的启动过程
- 情感分析[深度学习/机器学习]专业英语词汇分享
- 角色 RESOURCE、CONNECT、DBA具有的权限
- [BI项目记]-搭建代码管理环境之创建团队项目
- 实验任务(四)---恶意代码技术
- windows/linux下批量修改文件名以及文件名后缀
- Vue实现拖拽拼图滑块验证
- java移位加密_凯撒加密解密(java字母移位)
- 3.3. debug ip igrp
- Linux命令 ln
- python修改二进制文件_python二进制修改bcwav文件
- 有没有人知道这是为什么
- 基于centos 搭建 LAMP 环境,建立WordPress站点
- 会声会影浪漫婚礼视频——美到想哭
- 用计算机怎么转换器,电脑转换器怎么用 电脑转换器详解