一)MYSQL中的锁(知识补充)
可以通过In_use字段来进行判断是否针对于表进行加了锁
1)对于undo log日志来说:新增类型的,在事务提交之后就可以清除掉了,修改类型的,事务提交之后不能立即清除掉这些日志会用于mvcc只有当没有事务用到该版本信息时才可以清除
2)对于表锁来说,加锁非常快,开销非常小,直接修改加表锁的标记位就可以了,但是如果要加行锁,那么就是加锁非常慢,要找到对应的记录,表锁并发度很低,行锁并发度很高
3)注意:InnoDB存储引擎的行锁其实本质上是针对于索引加的锁,就是在对应的索引项上面做标记,不是针对于整个行记录加的锁,并且该索引不能失效,否则会从行锁升级成表锁,RR隔离级别下会升级成表锁,RC隔离级别下不会升级成表锁
4)假设在RR隔离级别下执行下面的SQL,select * from user where name="张三",此时where条件中的name字段没有索引,那么对于其他的Session对该表任何一条记录做修改操作都会被阻塞住,因为在RR隔离级别下,需要解决不可重复读问题和幻读问题,所以在进行遍历扫描索引记录的时候,为了防止扫描过的索引被其他事务修改也就是不可重复读问题,或者是间隙被其他事务插入记录,从而导致数据不一致,所以MYSQL的解决方案就是把所有扫描过的索引记录和间隙锁都加上;
5)意向锁就是一个表锁,就是为了防止别的事务对这条记录加锁的时候,需要扫描整张表进行排查这条记录是否被加了锁,就是当我们对表中的一个记录加锁的时候,就会加一个标识,告诉其他事务这个表中的某一条记录已经被加锁了,RR级别为了解决不可重复读问题和欢度问题不可避免地要引入一些机制;
6)间隙锁:很容易理解,就是在两条记录中加上了一把锁,在两行记录中的间隙一条不存在的记录加上了一把锁,间隙锁只有在可重复读隔离级别下才会生效,MYSQL默认隔离级别是RR,存在着幻读问题,但是间隙锁是可以解决幻读问题的,也就是说,只要在间隙范围内锁了一条不存在的记录会锁住整个间隙范围,不锁边界记录,这样就能防止其它Session在这个间隙范围内插入数据,就解决了可重复读隔离级别的幻读问题,是在索引和索引范围加锁,如果没加索引,就会变成表锁;
对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,然后将trx_id修改成删除操作的trx_id,同时在该条记录的头信息(recordheader)里的(deleted_flag)标记位写上true,来表示当前记录已经被删除,在查询时按照上面的规则查到对应的记录如果delete_flag标记位为true,意味着记录已被删除,则不返回数据
二)锁等待分析:
1)通过检查InnoDB_row_lock状态变量来分析系统上面的行锁的争夺情况,第一个参数是当前正在锁等待的事务的数量,第二个参数反馈了所有锁是其他事务阻塞的总时间的长短,第三个参数是每一次等待锁平均所花的时间,从系统启动到现在等待最长的一次锁最长的一次时间,从下面的分析可以看出,注意第一个参数和最后一个参数,最后一个参数是等待的总次数;
2)当上面三个字段的数据比较高的情况下,并且每一次等待的时间的次数也不少的情况,程序员就要开始分析系统为什么有这么多的锁等待,然后制定优化计划3)查看INFORMATION_SCHEMA系统库锁相关数据表,是系统库中的表
blocking_lock_id表示要加的锁,request_lock_id表示还没有获取到这把锁
‐‐查看事务 select * from INFORMATION_SCHEMA.INNODB_TRX; ‐‐查看锁 select*fromINFORMATION_SCHEMA.INNODB_LOCKS; ‐‐查看锁等待 select*fromINFORMATION_SCHEMA.INNODB_LOCK_WAITS; 释放锁,trx_mysql_thread_id可以从INNODB_TRX表里查看到 kill trx_mysql_thread_id ‐‐查看锁等待详细信息 show engine innodb status;
查看锁等待信息:show engine innodb status
大多数情况mysql可以自动检测死锁并回滚产生死锁的那个事务,但是有些情况mysql没法自动检测死锁,这种情况我们可以通过日志分析找到对应事务线程id,可以通过kill杀掉;