在MySQL的事务并发访问下,数据可能会出现一些问题,所以我们需要使用锁来规避这些问题。
根据锁的粒度可以分文表锁和行锁(MyISAM不支持),在逻辑上可以分为排他锁和共享锁。在MySQL中,对一行数据加锁,是为这一行数据的索引加锁,而不是为数据本身加锁。比如你在 where 条件后的字段没有索引,就会导致行锁失效,成为表锁。
MySQL的串行化读使用 next-key lock(间隙锁+行锁) 进行保证的,解决了事务的幻读问题。
比如隔离级别在串行化读下,执行 select * from user where id>8; MySQL就会在id>8的数据之间的间隙,和超出存储数据的id的空洞都加上了锁,这样的锁被称之为间隙锁。间隙锁都是左开右闭区间。
但是当一个事务执行select * from user where id>8,另一个inser id = 6的却依然执行不成功是什么问题呢?
我们之前提到过,通过where过滤条件查询添加间隙锁,where后面跟的条件必须是有索引的。在第一个事务执行时可能MySQL认为使用索引没有全盘扫描效率高,或者所差无几,那么MySQL就不会USE INDEX,所以就加不上间隙锁,而使用的是表锁。那么另一个事务在 INSERT 时就会阻塞。
当where后面的字段是辅助索引时,MySQL会加上行锁+间隙锁;
当字段是主键索引或者唯一索引时,MySQL只会加行锁。因为串行化读主要是为了解决幻读问题,只要防止当前where条件不会出现幻读现象就可以了,这样的话并发效率也相对高点。