锁与MySQL中的锁

锁是并发控制主要的技术手段。

悲观锁

悲观锁是建立在避免大量冲突更新的前提下使用的,无论怎样的更新操作都必须顺序执行。

为了解决大量的冲突更新,需要对数据添加排他锁

排他锁指的是仅拥有锁的情况下才可以更新,排除以外的更新操作。

如果成功,执行更新操作,否则,抛出异常提示执行失败,表明该数据正在被修改。

更新成功后,释放排他锁,该数据可用于其他更新操作。

乐观锁

乐观锁是建立在支持并发冲突更新的前提下使用的,仅在数据提交时来验证冲土与否。

为了解决并发的冲突更新,需要对数据添加版本标识

版本标识是利用数据的多版本化来实现数据的冲突检测,冲突的提交依赖版本的高低。

为数据增加一个新的属性版本标识,每当读取数据时,都会把数据的版本信息同时读取出来,每当需要更新数据时,都会数据对应的版本信息与上一次读取的版本信息做对比,只有版本信息相同(数据未被更改)时,才予以更新,否则认为数据已过期。

应用

多读的场景

多读的场景下,必然带有更少的冲突以及大量的并发读。

为了实现大量的并发读写,基于多版本的乐观锁的实现更适合。

多写场景

多写的场景下,数据均需要写入操作,此时可能需要考虑锁的粒度。

如果仅对单一数据进行大量的冲突写入,使用多版本化的乐观锁更加适合。

如果对不同数据的大量写入,使用悲观锁更加合适,避免了大量无效版本对比的开销。

实际的场景

Memcached使用CAS来解决冲突问题。

Redis通过WatchCAS来实现事务冲突的回滚。

传统关系型数据库中的行锁表锁都属于悲观锁。

Mysql中的MVCC属于乐观锁。

locking in MySQL

MySQL中常见的锁:行锁表锁

行锁

行级锁是MySQL中锁的力度最小的一种,只会当前操作的行进行加锁,但它开销大,加锁慢。

行锁锁的是聚簇索引

Innodb支持行级锁,通过对索引加锁来实现的。

表锁

表级锁是对当前操作的整个数据表加锁,它的实现就比较简单,开销小,但对整体性能价差,锁住期间无法对外提供其他服务。

InnoDBMyISAM都支持表级锁,具体可分为排他锁共享锁

共享锁、排他锁、意向锁

共享锁属于行锁,又称为读锁,允许其他用户读取数据,但任何事务都不可以更改数据。

1
select * from student lock in share mode;

排他锁属于行锁,又称为写锁,不允许其他用户的操作(包括写和读)。

1
select * from student for update;

意向锁属于表锁,在InooDB中会自动加意向锁。

意向锁分为两种,意向共享锁意向排他锁

执行insert/update/delete语句时,InnoDB会自动给数据添加意向排他锁,而执行select语句不会加锁。


意向锁存在的意义?

意向锁属于表锁,是在添加行锁前添加的。

为什么是行锁前添加?

由于意向锁是为了解决行锁与表锁的冲突

假设一种没有意向锁情况:

  • A添加了一个行锁;
  • B添加了一个表锁,由于A的行锁的存在,B只能通过遍历所有行锁来判断是否可以加表锁。

问题出现在第二部中的遍历行锁

因此,InooDB提供给了意向锁来标示当前表存在行锁,以此来避免表锁的冲突。