为什么要整理
- 当然是为了面试了
- 网上的文章没有想要的场景,比如 多事务的时候,如何判断间隙锁,x锁,ix锁等等,只是概念,本人愚钝找不到要领
环境配置
- mysql:8.0.28
- windows10
- 默认是innodb
表设计
create table order_detail
(
id int auto_increment
primary key,
order_id varchar(256) null,
order_date datetime null,
customer_name varchar(256) null,
price int null,
product_id int null,
order_status tinyint(1) null
);
create index order_detail_order_id_index
on order_detail (order_id);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (1, '1', null, null, null, null, null);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (2, '323', null, '3333', null, null, null);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (3, '324', null, '3333', null, null, null);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (4, '325', null, '3333', null, null, null);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (5, '423', null, '3333', null, null, null);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (6, '523', null, '3333', null, null, null);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (7, '623', null, '3333', null, null, null);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (8, '624', null, '3333', null, null, null);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (9, '625', null, '3333', null, null, null);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (10, '723', null, '3333', null, null, null);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (11, '823', null, '3333', null, null, null);
INSERT INTO sync.order_detail (id, order_id, order_date, customer_name, price, product_id, order_status) VALUES (13, '321', null, null, null, null, null);
锁的概念
感谢别人整理的文章(https://blog.csdn.net/bigbig1984/article/details/135046743) 不了解的建议先读一下
必备技巧
-
本人用的datagrep 其中有个框框可以按照mysqld的方式提交begin;commit; 这样我们就可以查询锁和事务的状态。
选择手动, 执行的时候这样
查看自己数据库锁等待时间
SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';
我的默认是50秒。
SELECT * FROM information_schema.innodb_trx; #查询执行的事务
SELECT * FROM performance_schema.data_locks; #查询锁的情况
- 建议自己弄一个单独的server,因为在其他环境中 ,真的看不过来,当然大神除外。
分析数据
- id为自增逐渐 ,
- order_id是索引,值为(1,321,323,324,325,423,523,623,624,625,723,823)
- gap区间分别为[2,321),[326,423),[424,523),[524,623),[626,723),[724,823)(这里有个问题,我定义的字符串,不知道这个gap会不会正确,因为没有数字更清晰)
要做的常见
查看单个插入和更新
插入已经有数值
insert order_detail (order_id) value (321);
查询 SELECT * FROM information_schema.innodb_trx;
发现 查看事务id为 1827
然后在查询 SELECT * FROM performance_schema.data_locks;
我们先分析这些
第一条这个表加了IX 也就是意向写锁
第二条给这行增加了 X,REC_NOT_GAP:X代表排他锁,REC_NOT_GAP代表行锁
第二条中,最后一列,因为是行数所以锁定的 order_id为319 ,主键id是14
我们在更新这条语句会发生什么,
它有个机制是如果锁等待超过上面默认的50秒 就会释放后来的语句(自测的时候要注意)
执行语句
update order_detail set customer_name='账单' where order_id='319'
第一条结果,是给表增加了IX 写意向锁
第二条结果,给行增加写锁,但是lock_status是waiting ,也就是需要等待上个释放之后才可以执行,超时则放弃
commit insert语句之后
对表增加了IX ;对行 分别对索引和主键增加了写锁;且增加了对索引的间隙锁 从
结论
- 如果发生了写操作的都会对表进行增加IX意向锁
- 按照事务的先后,如果出现锁的竞争,后来的loclstatus是waiting状态
- 当之前的锁被释放了,后面会继续增加本次要操作的锁
自己整理
当select for update 时候
1. 当存在值的时候会分别锁住 值旁边的间隙范围(存在范围锁范围)
2. 当不存在值的时候 ,只锁住范围内的值
不存在for update时候
1. 当更新范围的时候,相当于 对这个范围增加了 写锁其他不可以操作
2. 非范围的时候
1. 命中值的时候,其他对该值的写操作都会被阻塞
2. 非命中
1. 先insert的时候 不会缩范围
2. 先update的时候,会触发间隙锁不让insert
3. 也就是间隙锁是防止插入,但不会影响更新, 也就当update触发间隙锁的时候,不能insert。