MyISAM与InnoDB关于锁方面的区别:mysql
注:算法
实际上在不走索引的时候,InnoDB的实现方式和MyIsam的表锁方式不一样,单条索引记录上加锁,record lock锁住的永远是索引,而非记录自己,即便该表上没有任何索引,那么innodb会在后台建立一个隐藏的汇集主键索引,那么锁住的就是这个隐藏的汇集主键索引。因此说当一条sql没有走任何索引时,那么将会在每一条汇集索引后面加X锁(排他锁),此时想改变树型结构即索引结构的话,是会被锁住的,这个相似于表锁,但原理上和表锁是彻底不一样的sql
MyISAM适合的场景:数据库
InnoDB适合的场景:并发
数据库锁的分类:mvc
总结:ide
MyISAM默认使用的是表级锁,不支持行级锁。InnoDB默认用的是行级锁,也支持表级锁。不管是表级锁仍是行级锁,均分为共享锁和排他锁,它们的关系以下表所示(X:排他锁,S:共享锁):3d
事务并发访问引发的问题以及如何避免:指针
1.更新丢失:日志
即一个事务的更新覆盖了另外一个事务的更新;因为如今主流数据库都会自动加锁来避免更新丢失的状况,因此在数据库层面一般不会发生这个问题。例如mysql全部事务隔离级别在数据库层面上都可避免更新丢失
下图模拟了更新丢失的过程:
2.脏读(Dirty read):
即一个事务读到另外一个事务的未提交数据;该问题在READ-COMMITTED(读已提交)以上的事务隔离级别可避免
3.不可重复读(Non-repeatable read):
即事务A屡次读取同一数据,但事务B在事务A屡次读取的过程当中对该数据作了更新操做并提交,致使事务A屡次读取同一数据时结果不一致;该问题在REPEATABLE-READ(可重复读)以上的事务隔离级别可避免,这也是MySQL的默认隔离级别
4.幻读(Phantom read):
事务A读取以搜索条件相匹配的若干行数据,而事务B则对事务A查询匹配的数据进行了插入或删除操做,致使事务A屡次读取的结果集行数不一致;该问题在SERIALIZABLE(串行化)以上的事务隔离级别可避免,须要注意的是:在MySQL数据库中,REPEATABLE-READ事务隔离级别下也能够避免幻读
总结:
表象:快照读(非阻塞读)-- 伪MVCC(多版本并发控制)
内在:next-key锁(行级锁+gap锁)
首先咱们须要知道两个概念:当前读和快照读;当前读其实就是加了锁的增删改查语句,例:
之因此叫当前读,是由于读取的是当前记录的最新版本,而RR事务隔离级别下在读取数据以后还须要保证其余事务不能修改当前记录,那么就会对读取的记录加next-key锁,因此RR事务隔离级别下的当前读能够避免发生幻读现象:
快照读则是不加锁的非阻塞读,例如不加锁的普通select操做。但须要注意的是在串行化的事务隔离级别下,任何的增删改查操做都会被加锁。
在mysql中,读已提交隔离级别下,快照读和当前读都是读到一样的数据。而在可重复读隔离级别下,快照读读到的是开启事务时第一条select语句读到的快照版本数据,当前读则是会读到当前数据库中最新的数据。
RC、RR级别下的InnoDB的快照读(非阻塞读)是如何实现的:
事务对行的更新过程:
在以前的小节中,咱们了解到在MySQL的RR事务隔离级别下,是能够避免幻读的。但并不意味着快照读是避免发生幻读现象的根本,由于快照读只是读的发生变化前的历史数据。实际在RR及SERIALIZABLE事务隔离级别下真正防止幻读发生的缘由是事务对数据加上了next-key锁,而next-key锁由行锁和gap锁两部分组成。行锁就很少说了,gap锁才是重点,所谓gap就是索引树中插入新记录的间隙,而gap锁是用于锁定一个间隙范围但不包括记录自己,gap锁的目的是为了防止同一事务的两次当前读而致使出现幻读的状况。
gap锁只在RR和SERIALIZABLE事务隔离级别中存在,其余的隔离级别是没有的,因此RC和RU是没法避免幻读的。这里咱们主要讨论RR事务隔离级别下gap锁出现的场景:
where条件所有命中,只会加行锁:
走非惟一索引时会对该索引间隙加gap锁:
不走索引则会对表里全部的间隙加gap锁,其效果就相似于表级锁了,可是其代价比表级锁更大:
总结:
不管是当前读仍是快照读,在innodb的RR的事务隔离级别下均可以免幻读。在快照读的状况下,innodb经过mvcc来避免幻读;在当前读的状况下,innodb经过next-key锁来避免幻读。