Innodb索引和锁的学习笔记

附录:前段时间学习了下innodb锁的相关知识,对锁和事务有了大致理解,这里作个小总结。 mysql

1.Innodb事务和锁的关系。

   Innodb区别于MyISAM的两个特色就是Innodb对于事务的支持和对行锁的支持。事务要求了一组SQL语句的ACID特性,同时为了不对一行记录的并发更新,innodb自己会在必定状况下加锁,而后等语句所在的事务退出后(rollbak或者commit)释放锁。其实在autocommit=true时,一个sql自己就是一个事务。 sql

   Innodb在执行Update,Delete,Insert时会对记录加写锁(排他锁,加上排他锁后,不能再加共享锁和排他锁)。而Select语句不会对记录加锁。 数据库

 

   共享锁:SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。 并发

   排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE。 工具

 

举例: 学习

 

 

   如图,左侧事务加了排他锁(for update),右侧事务直接查询不会等待(不加锁),加排他锁失败,加共享锁失败(lock in share mode)。左侧事务提交或者回滚后,释放锁。 优化

 

2.Innodb的行锁特性。

   Innodb使用行锁加锁记录,也就是说会在加锁条件下对访问的具体行进行加锁,而不会锁住全表。这样可以大大提升表访问的吞吐量,减小没必要要的记录锁。而Innodb的行锁是使用索引实现的,所以有一下几点须要注意: spa

  •     若是对已一条加锁语句访问的数据走不了索引或者没加索引,其实他锁的是全表,这点须要注意。
  •     若是索引使用的是范围,那么他会锁住命中的记录,同时会锁住不存在的记录间隙防止插入(这一行并不存在),gap lock。

          如图 线程

          

    

       左边事务锁住了age>3的记录,那么很天然age=4的记录会被锁住。而在右边事务中,插入一条age=5个记录,而插入操做被hang住,这就是间隙锁。间隙锁是为了不幻象读的发生,即A事务批量update condition=x的记录,同时B事务插入了一条condition=X的记录,那么A事务提交后,发现仍然存在一条没有更新的记录,貌似出现了幻觉,这就是幻读。 htm

       由于间隙锁彷佛为了防止插入,因此update age=5并不锁表,由于记录并不存在- -。

  •     若是两个查询走不一样索引,可是却须要处理同一条记录,会竞争锁。
  •     虽然两个查询到的记录不一样,可是走的是同一个索引,那么依然会竞争锁。

   例如:



 
 learntransaction表在age加了索引,左边窗口查询age=122 AND id=6的记录,右边窗口查询age=122 and id=3的记录,能够发现二者的记录并不一样,可是却出现了锁竞争,由于两个公用了一个索引age=122。

  •     当where语句的查询字段涉及到多个索引时,mysql会优化sql决定走的索引,因此若是id也加了索引,那么索然在where语句里age在前面,但不必定走age的索引而走了id的索引。因此这个时候对于怎么加锁须要看具体索引的使用状况,建议使用explain工具查询执行计划判断。

        这里须要注意的是,慢查询致使数据库hang住并不必定是由于竞争锁,慢查询可能由于要更新的记录太多,致使sql迟迟没法完成,而innodb默认32个槽,也就是32个并发工做线程,当32个线程都在运行而没法接收新的sql时,数据就可能被hang住了,而与锁无关。

 

 

参考资料:

《深刻浅出MySQL——数据库开发、优化与管理维护》 http://book.51cto.com/art/200803/68127.htm

相关文章
相关标签/搜索