InnoDB和MyISAM的锁
InnoDB和MyISAM的行表锁
InnoDB默认是行级锁,支持表锁,也就在InnoDB中更新某条数据会对行上锁,如果是排他锁,那么其他的事务访问这一行的数据需要等锁释放之后才能进行,而对其他行数据是没有影响的。
MyISAM默认是表级锁,不支持行级锁,也就是在MyISAM中进行某条数据更新时,会对整个表上锁,所有的其他事务对表中对数据进行访问或者更新的时候都必须等那个事务释放表锁。
需要注意的是,当InnoDB不走索引的时候,就会默认上表级锁了。
InnoDB和MyISAM的区别和选择:
行锁与表锁的区别:
因为行级锁需要扫描命中对应的那一行才能上锁,所以上锁消耗的时间更大,而且容易出现死锁的问题。而表级锁只需要锁住整张表,所以上锁消耗并不大,并且不会出现死锁的问题。
死锁的一个例子:
事务1 | 事务2 |
---|---|
begin | begin |
update t set k = 1 where id = 1 | update t set k = 1 where id = 2 |
update t set k = 2 where id = 2 | update t set k = 1 where id = 1 |
commit | commit |
如上的例子,事务2在等待事务1释放id为1那一行的锁,而事务1在等待事务2释放id为1那一行的锁,这样就造成了死锁
MyISAM的适用场景:
- 并发度不高
- 增删改比较少,而查询比较多的情况
InnoDB适用的场景:
- 需要支持事务
- 并发度高
- 增删改比较多
为什么MyISAM查询比InnoDB快?
- InnoDB只有一个聚簇索引,其他都是非聚簇索引,当sql语句走非聚簇索引当时候需要进行两次索引查询。而MyISAM全都是非聚簇索引,而且索引的叶子节点都指向数据文件的地址,所以只需要走一次索引
- InnoDB在select的时候需要维护的东西比MyISAM多。1.
InnoDB 要缓存数据和索引,MyISAM只缓存索引块。2.innodb寻址要映射到块,再到行,MyISAM记录的直接是文件的OFFSET,定位比INNODB要快 - 以select count(*) 来说,InnoDB需要全表扫描,而MyISAM维护有一个值可以实时获取
共享锁和排他锁
InnoDB和MyISAM都拥有共享锁和排他锁,他们的兼容性如下:
事务T1共享锁+事务T2共享锁 = 兼容
事务T1共享锁+事务T2排他锁 = 不兼容
事务T1排他锁+事务T2共享锁 = 不兼容
事务T1排他锁+事务T2排他锁 = 不兼容
以InnoDB行锁为例,也就是只有某个事务对某一行实行了排他锁,那么这一行就不能被其他任何事务所操作。而对这一行实行了共享锁,其他事务还可以对这一行只能进行读操作。
例子:
我们开启两个事务,并把Auto-Commit设置为false,也就是不会自动commit,我们需要在执行完对应的语句之后再调用commit才会对事务进行提交。
我们按照以下对逻辑进行测试:
- 事务1
select * form t where id = 3;
- 事务2
update t set name = xxx where id = 3;
可以神奇地发现事务2竟然没有被阻塞,这是因为Mysql对select进行了优化,不会阻塞其他事务。我们可以在select 语句后面加上lock in share mode,就可以对语句对应对行设置共享锁了,我们重新开启测试
- 事务1
select * form t where id = 3 lock in share mode;
- 事务2
update t set name = xxx where id = 3;
这时候事务2就会一直阻塞了,这样子就成功展示出了共享锁与排他锁冲突的场景。
这时对事务1进行commit,事务1就会释放行级锁,这时候事务2对update语句就会往下运行不会阻塞了。