锁分类
- 性能分有乐观锁和悲观锁,前者适用读操作较多的业务,后者适用写操作较多的业务.
- 操作分有行锁,表锁.
- 数据库操作类型有读锁和写锁(都属于悲观锁)
乐观锁
只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,否则执行操作(一般都是用version)
悲观锁
操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据
表锁
操作锁住整张表.开销小,加锁快;锁力度大,锁的冲突概率越高,并发度较低;一般用在表的数据迁移
-- 锁表,主要是迁移的时候,防止数据增加
lock table users read;
-- 查看表锁
show open tables where in_use>=1;
-- 删除表锁
unlock tables;
在锁表的过程中,不能修改表数据
行锁
锁住一行数据.开销大,加锁慢(需要遍历到该数据);锁粒度小,锁冲突较低,并发度高
InnoDB行锁实际上是在索引对应的项上做标记;如果该索引失效或者删除,就会升级行锁为表锁(RR级别会升级,RC不会)
升级的大致原因
RR级别需要解决不可重复读以及幻读问题,所以为了防止索引被其他事务修改(不可重复读)或被其他事务新增记录(幻读--主要在间隙中新增),从而导致数据问题,MySQL解决方案扫描索引记录和间隙都上锁.
间隙锁
顾名思义,间隙就是两值间的空隙,只在可重复读(repeattable-read)的隔离级别下才会生效.综合来讲就是间隙锁能在可重复读下解决幻读问题.
开启可重复读
-- 可重复读
set tx_isolation='repeatable-read';
begin;
select * from users;
commit;
间隙可知(3,20)
故在(3,20)间插入数据,就会出现数据等待
间隙就是锁住该数据的间隙范围,防止插入数据,解决幻读问题.
锁等待
执行innodb_row_lock变量来分析
-- 锁状态分析
show status like 'innodb_row_lock%';
主要关注 lock_time_avg 等待平均时长 lock_waits 等待总次数 lock_time 等待总时长
等待次数很高,等待时长也挺长,需要根据分析着手制定优化计划.
查看information_schema系统锁表
-- 查看事务
SELECT * from information_schema.INNODB_TRX;
-- 查看锁,8后换成data_locks
SELECT * from information_schema.INNODB_LOCKS;
-- 查看锁等待,8后换成 data_lock_waits
SELECT * from information_schema.INNODB_LOCK_WAITS;
-- 释放锁.trx_mysql_thread_id,从INNODB_TRX 查看
kill trx_mysql_thread_id;
-- 查看锁详细情况
show engine innodb statsu