读锁:也叫共享锁,Share Lock,S锁,当一个事务添加读锁后,其他事务也可以获取这个共享锁来读取数据,但是不能进行写数据(获取读锁的事务只能读,不能写),只有等到所有的读锁都释放了,才能写数据
上读锁,而且是行级读锁
select * from student where name=‘小明’ lock in share mode;
写锁:也叫排他锁,Exclusive Lock,X锁,当一个事务添加了写锁之后,其他事务无法获取这个锁,无法读也无法写,只能等待当前事务释放写锁
上写锁,而且是行级写锁
select * from student where student_id=1 for update
行级锁和表级锁:MyIsam引擎只支持表级锁,InnoDB引擎既支持表级锁,也支持行级锁
表级锁:mysql中粒度最大的锁,对整张表加锁,实现起来简单,资源消耗也比较少,不会出现死锁,但是由于其粒度太大,触发锁冲突的概率也是最大的,并发写的情况下性能非常差
表级锁针对非索引字段加锁
行级锁:mysql中粒度最小的锁,只对当前操作的行记录(一行或者多行)进行加锁,大大减少了锁冲突的情况,但是加锁的开销也是最大的。而且会出现死锁
行级锁针对索引字段加锁
行锁可以进一步进行分类:记录锁,间隙锁,临键锁,这三个锁都是写锁
(1)记录锁 record locks
仅仅锁住一行
这个就是记录锁
SELECT * FROM `test` WHERE `id`=1 FOR UPDATE;
(2)间隙锁 gap lock
左开右开区间,也就是不包括双端端点
创建一张表,表里面只有两个字段id 和name
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', '小红');
执行下面的sql语句,发现
BEGIN;
SELECT * FROM `test` WHERE `id` BETWEEN 5 AND 7 FOR UPDATE;
INSERT INTO `test` (`id`, `name`) VALUES (3, '小张1'); # 正常执行
INSERT INTO `test` (`id`, `name`) VALUES (4, '小白'); # 正常执行
INSERT INTO `test` (`id`, `name`) VALUES (6, '小东'); # 阻塞
INSERT INTO `test` (`id`, `name`) VALUES (8, '大罗'); # 阻塞
INSERT INTO `test` (`id`, `name`) VALUES (9, '大东'); # 阻塞
INSERT INTO `test` (`id`, `name`) VALUES (11, '李西'); # 阻塞
INSERT INTO `test` (`id`, `name`) VALUES (12, '张三'); # 正常执行
COMMIT;
可以看到,(5, 7]、(7, 11] 这两个区间,都不可插入数据,其它区间,都可以正常插入数据。所以所以锁住的是[5,11]
(3)临键锁 next key lock 可以理解为一种特殊的间隙锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭区间的数据(临键锁只与非唯一索引有关,唯一索引不存在临键锁)
什么时候会加上临键锁:select * from table for update;
或者update XX的时候就会获取到该行记录的临键锁
现在在事务A中执行以下命令:(只开启事务,不提交事务)
start transaction;
update student set email='zm@alibaba-inc.com' where age=26;
更改赵敏的email邮箱 ,此时会锁住的是(26,77]
现在事务B执行下面的命令:
start transaction;
insert into student values("s010","牛牛",28,’女‘,“13344453233”,“2658948489@qq.com”,“1988-02-11“,0);
commit;
发现没有插入成功,因为你插入的age=28,除在被锁住的age=(26,77] 区间内,没有拿到这把临键锁的事务B无法插入成功
只有事务A提交了,才会不锁住这个区间,事务B才能插入成功