Pessimistic Concurrency Control
悲观锁是假设数据冲突的可能性很大,每次更新数据都会锁定数据,直到更新操作完成。
在对数据进行更新之前,需要对数据添加排他锁,如果成功,执行更新操作,否则,抛出异常提示执行失败,表明该数据正在被修改。更新成功后,释放排他锁,该数据可用于其他更新操作。
Optimistic Concurrency Control
乐观锁是假设数据一般不会造成冲突,只有在数据进行提交更新的时候,才会对数据的冲突与否进行验证,如果冲突返回错误信息,待用户进一步处理。
为数据增加一个新的属性版本标识,每当读取数据时,都会把数据的版本信息同时读取出来,每当需要更新数据时,都会数据对应的版本信息与上一次读取的版本信息做对比,只有版本信息相同(数据未被更改)时,才予以更新,否则认为数据已过期。
由于乐观锁的版本对比特性,每次更新都需要进行版本检查,造成了开销,所以它更适合多读得场景,也就是冲突较少的情况(避免过多的版本对比的开销);反之,写操作较多,冲突较多的场景,更适合使用悲观锁,这样不需要重复的对比开销。
memcached使用CAS(compare and set)乐观锁来解决冲突问题。
redis使用乐观锁来实现事务操作(redis中的事务是把事务中的操作加入到一个执行队列中,直到exec命令开始执行)。
传统关系型数据库中的行锁、表锁都属于悲观锁。
mysql中常见的锁:行锁、表锁、页锁。
row-level locking
行级锁是mysql中锁的力度最小的一种,只会当前操作的行进行加锁,但它开销大,加锁慢。
Innodb支持行级锁,但它的实现是通过对索引加锁来实现的,因此只有通过索引来检索数据才会触发行级锁。
由于innodb中的行级锁是逐步获取的,那么有可能造成死锁。
table-level locking
表级锁是对当前操作的整个数据表加锁,它的实现就比较简单,开销小。
它包括:排他锁和共享锁。
InnoDB和MyISAM都支持表级锁。
page-level locking
页级锁是介于行锁和表锁粒度之间的一种锁,BDB支持,但可能造成死锁。