Mysql InnoDB 锁总结
锁类型
排他锁(写锁、X锁)
会阻塞其他事物读和写
共享锁(读锁、S锁)
会阻塞其他事物修改表数据
意向锁
意向锁与行锁互不排斥,意向锁之间互不排斥,意向锁与表锁互斥!
锁粒度
行锁
开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高
表锁
开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低
页锁
开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
活锁与死锁
活锁
如果事务T1封锁了数据对象R后,事务T2也请求封锁R,于是T2等待,接着T3也请求封锁R。当T1释放了加载R上的锁后,系统首先批准T3的请求,T2只能继续等待。接着T4也请求封锁R,T3释放R上的锁后,系统又批转了T4的请求。这样的一直循环下去,事务T2就只能永远等待了,这样情况叫活锁
死锁
当两个事务分别锁定了两个单独的对象,这时每一个事务都要求在另一个事务锁定的对象上获得一个锁,因此每一个事务都必须等待另一个事务释放占有的锁,这种情况叫死锁
InnoDB行锁总结
行锁是针对索引的
故某索引相同的记录都会被加锁,会造成索引竞争,这就需要我们严格设计业务sql,尽可能的使用主键或唯一索引对记录加锁。很多时候,扫描一个表,由于无索引,往往会导致整个表被锁住(不是表锁),建立合适的索引可以防止扫描整个表
记录锁
它是建立在索引记录上的锁
间隙锁
锁定一个范围,但不包括记录本身
next-key锁
记录锁加间隙锁的组合。也就是说next-key锁技术包含了记录锁和间隙锁
有时在开发过程中我们会发现,在INSERT的时候会锁定相邻的键,其实这是一个next-key锁技术,MySQL使用这个技术来避免幻读
死锁总结
产生死锁的必要条件
- 禁止抢占
- 持有和等待
- 互斥
- 循环等待
- 预防死锁就是至少破坏这4个条件中的一项
InnoDB处理死锁的机制
发现有循环等待的现象,立即rollback开销更小的事务,也就是插入、修改、删除了更少记录的事务
死锁预防
- 经常提交你的事务。小事务更少地倾向于冲突。
- 以固定的顺序访问你的表和行。这样事务就会形成定义良好的查询并且没有死锁。
- 将精心选定的索引添加到你的表中。这样你的查询就只需要扫描更少的索引记录,并且因此也可以设置更少的锁定。
- 不要把无关的操作放到事务里面。
- 在并发比较高的系统中,不要显式加锁,特别是在事务里显式加锁。如SELECT…FOR UPDATE语句,如果是在事务里(运行了START TRANSACTION或设置了autocommit等于0),那么就会锁定所查找到的记录。
- 尽量按照主键/索引去查找记录,范围查找增加了锁冲突的可能性,也不要利用数据库做一些额外的计算工作。比如有些人会用到“SELECT…WHERE…ORDER BY RAND();”这样的语句,由于类似这样的语句用不到索引,因此将导致整个表的数据都被锁住。
- 优化SQL和表设计,减少同时占用太多资源的情况。比如说,减少连接的表,将复杂SQL分解为多个简单的SQL。