大家好,我是树哥。MySQLInnodb的锁可以说是执行引擎的并发基础。只有加了锁才能保证数据的一致性。众所周知,我们都知道Innodb有全局锁、表级锁、行级锁三种,但是你知道什么时候用表锁,什么时候用行锁吗?虽然我对MySQL的知识点还是比较熟悉的,但是树哥第一次看到这个问题的时候还是有点懵。我真的没有从这个角度考虑过。你可以暂时思考1分钟答案,稍后我会带你去揣摩这道题。对于这个问题,我只能大概想到一些片段,例如:对于表级锁,在执行DDL语句修改表结构时,会用到表级锁。对于行级锁,一般默认使用行级锁,貌似必须匹配一个索引。以上是我大致想到的答案。不知道大家是不是和我想的一样的答案呢?带你回顾一下MySQL锁!文章思维导图对于数据库来说,它的锁作用域可以分为:全局锁表级锁行级锁全局锁全局锁就是对整个数据库实例加锁。MySQL提供了一种添加全局读锁的方法,命令是Flushtableswithreadlock(FTWRL)。当需要使整个库处于只读状态时,可以使用该命令,然后其他线程的以下语句将被阻塞:数据更新语句(数据的增删改查)、数据定义语句(包括建表、修改表结构等)和一个更新事务的commit语句。你可以理解为全局锁基本上锁住了所有数据的变化语句。全局锁的典型应用场景是整个数据库的逻辑备份,即选择并保存整个数据库中的每一个表。上面提到全局锁会锁住所有的change语句,但这只是针对MyISAM存储引擎而言。对于Innodb来说,它可以使用MVCC来实现数据的一致视图,这样就可以在不锁定整个数据库的情况下实现整个数据库的数据备份。表级锁表级锁可以分为三种类型:表锁、元数据锁和意向锁。表锁表锁,顾名思义就是锁定某个表。那么什么时候会用到表锁呢?一般情况是对应的存储引擎没有行级锁(例如:MyIASM),或者对应的SQL语句没有匹配到索引。对于第一种情况,由于对应的存储引擎不支持行锁,所以只能使用粗粒度的锁来实现,这样也比较容易理解。对于第二种情况,如果存储引擎支持行锁,但是对应的SQL没有使用索引,那么此时会进行全表扫描,此时也会使用表锁。比如下面的语句没有指定查询列,或者指定了查询列但是没有使用索引,那么就会直接锁住整张表。//没有指定查询列select*fromuser;//指定了查询列,但没有使用索引select*fromuserwherename='zhangsan';上面提到的索引可以说是判断是否会使用行级锁的关键。但是我想到了一个问题:如果查询或者更新使用了索引,但是查询或者更新的数据特别大,占了整个表的80%或者更多,这时候会不会使用表锁或者行锁呢?这是一个非常有趣的问题。有兴趣的朋友可以拿一张测试表自己验证一下。这个问题以后有机会再说。元数据锁元数据就是指我们表结构的这些元数据。元数据锁(MetadataLock)自然是我们在执行DDL表结构变更语句时加在表上的锁。那么什么时候使用元数据锁,表级锁呢?当我们对表进行增删改查时,都会加MDL读锁;当我们要对表结构进行更改时,我们将添加MDL写锁。意向锁意向锁本质上是用空间换取时间的产物,是提高行锁效率的东西。在InnoDB中,当我们锁定一条记录时,为了提高并发性,我们通常只锁定这一行记录,而不是锁定整个表。当我们需要对整张表加X锁时,我们需要遍历整张表的记录。如果每条记录都没有加锁,我们可以给整个表加一个X锁。而这个遍历过程是非常耗时的,这时候意向锁就诞生了。意向锁其实就是标记表是否被锁定。如果某条记录被锁定,那么必须获得该表的意向锁。所以当我们需要判断这张表的记录是否被加锁时,直接判断意向锁即可,减少了遍历时间,提高了效率。这是典型的以空间换时间的做法。那么什么时候使用意向锁呢?很简单,就是在对表中的行记录加锁的时候,会用到意向锁。行级锁叫了半天,终于来到了行级锁。需要知道的是,行级锁是需要存储引擎支持才能生效的存储引擎级锁。目前MyISAM存储引擎不支持行级锁,而Innodb存储引擎支持行级锁。MySQL级别支持全局锁和表级锁。那么什么时候使用行级锁呢?当CRUD匹配索引时,InnoDB使用行级锁。如果没有匹配到的索引,那么就直接使用表级锁。小结在文章的最后,我们来回顾一下开头提出的问题:Innodb什么时候使用表锁,什么时候使用行锁?表级锁包括:表锁、元数据锁和意向锁。对于表锁,当存储引擎不支持行级锁时使用表锁。当SQL语句与索引不匹配时,使用表锁。对于元数据锁,在增删改查表的时候加上MDL读锁。当对表结构进行更改时,将添加MDL写锁。对于意向锁,意向锁用于锁定表中的行记录。对于行级锁,CRUD匹配索引时使用行级锁。最后附上本文的思维导图,方便大家回顾本文的内容。文章思维导图
