InnoDB关于事务、锁、MVCC专题( 二 )

mysql默认的,会存在幻读;

  • serializable(串行化):顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁” 。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行 。可以解决脏读、不可重复读和虚读---相当于锁表 。
  • 备注:虽然serializable级别可以解决所有的数据库并发问题,但是它会在读取的每一行数据上都加锁,这就可能导致大量的超时和锁竞争问题,从而导致效率下降 。所以我们在实际应用中也很少使用serializable,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别 。
    锁为什么要加锁如果有多个并发请求存取数据,在数据就可能会产生多个事务同时操作同一行数据 。
    也就是我们上面说到的在并发情况下会发生的这些问题,
    如果并发操作不加控制,不加锁的话,就可能写入了不正确的数据,或者导致读取了不正确的数据,破坏了数据的一致性 。因此需要考虑加锁
    InnoDB的七种锁共享/排他锁InnoDB呢实现了两种标准的行级锁:共享锁(简称S锁)、排他锁(简称X锁) 。
    • 共享锁:简称为S锁,在事务要读取一条记录时,需要先获取该记录的S锁 。
    • 排他锁:简称X锁,在事务需要改动一条记录时,需要先获取该记录的X锁 。
    如果事务T1持有行R的S锁,那么另一个事务T2请求访问这条记录时,会做如下处理:
    • T2 请求S锁立即被允许,结果 T1和T2都持有R行的S
    • T2 请求X锁不能被立即允许,此操作会阻塞
    如果T1持有行R的X锁,那么T2请求R的X、S锁都不能被立即允许,T2 必须等待T1释放X锁才可以,因为X锁与任何的锁都不兼容 。
    兼容性 SX S兼容不兼容 X 不兼容 不兼容意向锁意向锁是一种不与行级锁冲突的表级锁 。未来的某个时刻,事务可能要加共享或者排它锁时,先提前声明一个意向 。注意一下,意向锁,是一个表级别的锁 。
    因为InnoDB是支持表锁和行锁共存的,如果一个事务A获取到某一行的排他锁,并未提交,这时候事务B请求获取同一个表的表共享锁 。因为共享锁和排他锁是互斥的,因此事务B想对这个表加共享锁时,需要保证没有其他事务持有这个表的表排他锁,同时还要保证没有其他事务持有表中任意一行的排他锁 。
    然后问题来了,你要保证没有其他事务持有表中任意一行的排他锁的话,去遍历每一行?这样显然是一个效率很差的做法 。为了解决这个问题,InnoDB提出了意向锁 。
    如果一个事务A获取到某一行的排他锁,并未提交,这时候表上就有意向排他锁和这一行的排他锁 。这时候事务B想要获取这个表的共享锁,此时因为检测到事务A持有了表的意向排他锁,因此事务A必然持有某些行的排他锁,也就是说事务B对表的加锁请求需要阻塞等待,不再需要去检测表的每一行数据是否存在排他锁啦 。这样效率就高很多啦 。
    记录锁记录锁是最简单的行锁,仅仅锁住一行 。如:SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE,如果c1字段是主键或者是唯一索引的话,这个SQL会加一个记录锁(Record Lock)
    记录锁永远都是加在索引上的,即使一个表没有索引,InnoDB也会隐式的创建一个索引,并使用这个索引实施记录锁 。它会阻塞其他事务对这行记录的插入、更新、删除 。

    经验总结扩展阅读