|
1 2 3 4 |
mysql8版本 SELECT * FROM USER FOR SHARE mysql8之前的版本 SELECT * FROM USER lock in share mode |
|
1 |
SELECT * FROM USER FOR UPDATE |
共享锁和共享锁之间不阻塞,共享锁和排他锁之间阻塞,排他锁和排他锁之间阻塞。
表锁:对表进行加锁,颗粒度大效率高并发低;MYISAM只有表锁
页锁:DBD引擎独有的。
行锁:InnoDB特有的,锁的是索引并不是行数据本身(索引项),当操作数据(update/delete)不是索引的时候,RR模式下会升级为表锁,RC不会升级;
意向锁:InnoDB引擎为了提高判断效率,对数据行加锁(锁的是索引那里)的时候引入了意向锁的概念
间隙锁(Gap Look):对操作的区间加一个开区间锁,RR隔离级别独有的,解决了幻读的问题
临键锁(Next-key Look):间隙锁+行锁组成的一个闭区间,
|
1 2 3 4 5 6 7 8 |
-- 手动加表锁 lock 表名称 read/write,表2 read/write;
-- 查看表上加的锁 in_use 多少线程在使用 name_locked 是否加了锁 show open tables;
-- 删除表锁 unlock tables; |
关于RR级别行锁升级为表锁的原因?
在RR隔离界级别下,为了防止出现不可重复读和幻读情况,在遍历聚集索引的时候,为了防止其他事物操作数据(不可重复读)和间隙被插入问题(幻读),导致数据不一致,因此会在所有扫描到的索引记录和间隙加上锁。
这并不是对整张表加锁,而是精确地对命中范围内的记录和间隙加锁。当然,如果部分记录已被其他事务加锁,也可能导致当前事务出现等待或死锁。
MYISM在select的时候加表读锁,inster,update,delete的时候加表写锁;
InnoDB在执行select(非串行化隔离级别)的时候不加锁,在inster,update,delete的时候加行锁;
虽然在锁的性能开销上行锁更大, 但是整体使用上效率远远高于MYISM的表锁,也要使用得当,否则会出现死锁现象反而降低性能
|
1 |
show variables like '%innodb_row_lock%' |
对对应的状态进行分析,对于等待长次数高的,需要分析为什么会有这么多等待,然后优化。
查看近期的死锁日志:show engine innodb status;
|
1 2 3 4 5 6 7 8 9 10 |
查看事物 SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX; // <8.0 查看锁 SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; // <8.0 SELECT * FROM performance_schema.data_locks; // 8.0 查看锁等待 SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS; // <8.0 SELECT * FROM performance_schema.data_lock_waits; //8.0 释放锁 KILL trx_mysql_thread_id; |
减少锁的范围颗粒度
降低事物隔离级别
进来用索引,防止锁升级
控制事物大小,设计锁资源的最后执行
对同一行数据有不同的版本控制,可重复读和读已提交都是通过MVCC实现的;
undolog版本链和read view(一致性视图)机制:
不同事物会开启不同的版本链,在隐藏字段trx_id中存储,回滚标记roll_pointer,RR级别下,开启事物会生成 read view,后续操作不会改变(RC每次都生成新的read view);
这个read view是有,当前未提交的事物trx_id数组(数组里id最小的为min_id),和已创建的最大的事物trx_id(max_id)组成,任何事物查询都需要从版本链里最新数据逐一和read view对比从而获得最终的快照数据;
|
1 |
min_id= X; 未提交区间[*,*] ; max_id=Y; |
比对规则:
若X<=trx_id>=Y,分为两种情况:

删除数据其实是update的一种特情况,首先会从版本链复制一份最新的,然后trx_id改成删除的trx_id,同时该记录的头信息标记delete_flag写成true,后续查询不返回;
注意:
begin/start transaction不是事物的起点,当执行修改操作或者排他锁的时候才会事物申请一个真正的事物id。