表锁
加读锁
加写锁
案例总结
读锁会阻塞写请求,不会阻塞读请求;写操作会阻塞读写操作。
表锁分析
手动加锁
lock table 表名称 read(write),表名称2 read(write)…
释放表锁
unlock tables;
查看哪些表被加锁了
show open tables;
分析表锁定
show status like ‘table%’;
mysql> show status like 'table%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Table_locks_immediate | 105 |
| Table_locks_waited | 0 |
| Table_open_cache_hits | 41 |
| Table_open_cache_misses | 4 |
| Table_open_cache_overflows | 0 |
+----------------------------+-------+
可以通过检查table_locks_waited
和table_locks_immediate
状态变量来分析系统上的表锁定。
table_locks_waited
表示出现表级锁定争用而发生等待的次数(不能立即获取锁的次数,每等待一次锁值加1)。此值高说明存在严重的表级锁争用情况
table_locks_immediate
表示产生表级锁定的次数,表示可以立即获取锁的查询次数,每立即获取锁值加1。
行锁
行锁就是一锁锁一行或者多行记录,mysql的行锁是基于索引加载的,所以行锁是要加在索引响应的行上,即命中索引,如下图所示:
数据库表中有一个主键索引和一个普通索引,Sql语句基于索引查询,命中两条记录。此时行锁一锁就锁定两条记录,当其他事务访问数据库同一张表时,被锁定的记录不能被访问,其他的记录都可以访问到。
加锁
打开两个窗口,我们在窗口A中根据id更新一条记录,然后在窗口B中也执行相同的SQL语句看看
窗口A先修改了id为3的用户信息后,还没有提交事务,此时窗口B再更新同一条记录,然后就提示Lock wait timeout exceeded; try restarting transaction ,由于窗口A迟迟没有提交事务,导致锁一直没有释放,就出现了锁冲突,而窗口B一直在等待锁,所以出现了超过锁定超时的警告了。
但是,此时我们如果去更新id为3它旁边的记录看看会出现怎样的情况,我们新打开一个窗口更新id为2的记录看看。
可以看到,在窗口B中更新id为3的记录报错,但是在窗口C中我们可以更新id为2的记录,这说明此时锁定了id为3的记录但是并没有锁定它旁边的记录。
在mysql中,行锁又衍生了其他几种算法锁,分别是 记录锁、间隙锁、临键锁;我们依次来看看这三种锁
记录锁
间隙锁
临键锁
行锁分析
show status like ‘%innodb_row_lock%’;
Innodb_row_lock_current_waits: 当前正在等待锁的数量
Innodb_row_lock_time: 等待总时长。从系统启动到现在一共等待的时间
Innodb_row_lock_time_avg: 平均等待时长。从系统启动到现在平均等待的时间
Innodb_row_lock_time_max: 最大等待时长。从系统启动到现在最大一次等 待的时间
Innodb_row_lock_waits: 等待次数。从系统启动到现在一共等待的次数
行锁案例:https://zhuanlan.zhihu.com/p/52678870
行锁分析:https://blog.csdn.net/JYLLJY/article/details/95472063