MyISAM与InnoDB关于锁方面的区别:
注:
实际上在不走索引的时候,InnoDB的实现方式和MyIsam的表锁方式不同,单条索引记录上加锁,record lock锁住的永远是索引,而非记录本身,即使该表上没有任何索引,那么innodb会在后台创建一个隐藏的聚集主键索引,那么锁住的就是这个隐藏的聚集主键索引。所以说当一条sql没有走任何索引时,那么将会在每一条聚集索引后面加X锁(排他锁),此时想改变树型结构即索引结构的话,是会被锁住的,这个类似于表锁,但原理上和表锁是完全不同的
MyISAM适合的场景:
InnoDB适合的场景:
数据库锁的分类:
总结:
MyISAM默认使用的是表级锁,不支持行级锁。InnoDB默认用的是行级锁,也支持表级锁。无论是表级锁还是行级锁,均分为共享锁和排他锁,它们的关系如下表所示(X:排他锁,S:共享锁):
事务并发访问引起的问题以及如何避免:
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锁来避免幻读。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。