1.首先创建一个user表
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int DEFAULT NULL COMMENT '年龄',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1321800983473774597 DEFAULT CHARSET=utf8;
为表中的列name创建一个二级索引
CREATE INDEX name_index ON user (name)
插入五条数据如图所示
id | name | age | createtime | updatetime | |
1 | Jone | 18 | [email protected] | ||
3 | Tom | 150 | [email protected] | ||
4 | Mark | 23 | [email protected] | ||
5 | Lili | 18 | @cm | ||
8 | olol | 66 | @161.com |
2.条件列无索引 事务执行锁定读会引发的锁表
锁定读介绍:以下四种类型的语句都是先加各种锁,然后再进行读取。带有update的和DELETE都是排他锁,SELECT ....LOCK IN SHARE MODE就是共享锁(重点)
SELECT ....LOCK IN SHARE MODE |
SELECT ...FOR UPDATE; |
UPDATE... |
DELETE... |
我们使用udpate来进行演示
1.我们先执行事务1
##事务1
begin;##开启事务
update user set age=50 where email='@cm';
#此处没有用到索引列,必然会走全表扫描


注意:此时事务1还没有提交。以下的所有事务1都是未提交状态(就不一一赘述)
2.1此时我们执行事务2,id增加插入
(事务2是个隐式事务 执行完会自动提交事务)
##事务2 隐式事务
insert into user values (9,"boom",'22','ddd',NOW(),NOW());
此时事务2会陷入获取锁的过程而阻塞。阻塞超时后直接报异常
2.2 假设我们执行了事务1后,执行以下语句 事务3
执行了update语句还是锁表
综上2.1和2.2得出一个结论:只要锁定读语句走全表扫描,会进行锁表,更新一条或者多条数据,都会进行锁表,所以应该善用索引。
3.锁定读 有索引的情况之一(走唯一索引)
1.等值查找:锁定读只会加record lock ,不会加gap lock
事务1
事务2
此时插入数据是成功的,因为并没有加gap lock,加的是record lock
2.范围查找:加的是gap lock
事务1
事务2
此时事务2获取锁超时,直接返回异常
2.1假设我们在事务1开启的情况下,想修改id=5的数据,会发生什么?
此时获取成功了。说明等值(唯一索引情况下)加的是record lock
2.2 假设我们在事务1开启的情况下,想修改id=4的数据,会发生什么?
此时id=4的数据修改成功,证明了gap锁,大于5的所有数据 还有锁住查询条件8和5之间的数据
3.锁定读(聚簇索引,二级索引 )
1.还是和上面的事务1一样,现在我们探讨的是,如果我们使用了update语句修改的列带有索引。那么此时也要将索引锁住,锁住索引的锁用的是record lock。
事务1
事务2.此时我们使用共享锁来读取锁,然后等待锁,超时
现在我们使用索引范围匹配
事务1 二级索引 按字母进行排序 JLM字母开头这样的顺序
事务2 这个共享锁 是以M开头的,肯定中标了
我们再来看以J开头的会不会中标
很明显J开头的并不会中标,符合gap lock
小结一下:索引也是gap锁。但是锁住聚簇索引就使用了record 锁。反之,如果我们在聚簇索引中更改了一条数据,更改的列涉及索引列,那么此时就使用record锁住二级索引
补充:如果有索引下堆,那么可能不用回表,从而不使用record锁锁住聚簇索引的数据