提示:文章先作为初版,等后续时间充足后,补充更深的内容
MySql锁的类型
一、分类
基于锁的属性【读写】分类:共享锁【读】、排他锁【写】。
基于锁的粒度【范围】分类:行级锁(innodb ) 、表级锁 ( innodb 、myisam)、页级锁( innodb引擎)、记录锁、间隙锁、临键锁。
基于锁的状态分类:意向共享锁、意向排它锁。【加锁效率,锁的大小优先级】
二、详细
锁的属性
共享锁(share lock):共享锁又称读锁,简称S锁;当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加持写锁。共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复读的问题。
排他锁(exclusive lock)∶排他锁又称写锁,简称×锁;当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。排他锁的目的是在数据修改时候,不允许其他人同时修改,也不允许其他人读取,避免了出现脏数据和脏读的问题。
锁的粒度
【范围越小越详细越麻烦】
表锁(table lock)︰表锁是指上锁的时候锁住的是整个表,当下一个事务访问该表的时候,必须等前一个事务释放了锁才能进行对表进行访问;特点:粒度大,加锁简单,容易冲突
行锁:行锁是指上锁的时候锁住的是表的某一行或多行记录,其他事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问,特点:粒度小,加锁比表锁麻烦,不容易冲突,相比表锁支持的并发要高
记录锁(Record lock) :记录锁也属于行锁中的一种,只不过记录锁的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的某一条记录,加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题
页锁:页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁.表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。特点:开销和加锁时间界于表锁和行锁之间,会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
间隙锁:是属于行锁的一种,间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻ID之间出现空隙则会形成一个区间,遵循左开右闭原则。范围查询并且查询未命中记录,查询条件必须命中索引、间隙锁只会出现在REPEATABLE_READ(重复读)的事务级别中
临键锁(Next-Key lock):也属于行锁的一种,并且它是INNODB的行锁默认算法,总结来说它就是记录锁和间隙锁的组合,临键锁会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙空间也会锁住,再之它会把相邻的下一个区间也会锁住
乐观锁和悲观锁
乐观锁和悲观锁是两种常见的锁策略,用于解决多线程或多进程并发访问数据时的数据一致性问题。
悲观锁是一种悲观的认为并发环境下会出现数据不一致的锁策略,它在访问共享数据之前,会先加锁,防止其他线程或进程对共享数据进行修改。悲观锁的典型应用场景是数据库的行级锁和表级锁,以及 Java 中的 synchronized 关键字和 ReentrantLock 类。悲观锁实现相对简单,但会增加系统的开销,同时也会降低并发性能。
乐观锁则是一种乐观的认为并发环境下不会出现数据不一致的锁策略,它不会加锁,而是在访问共享数据时,先假设不会发生冲突,直到实际修改时才进行冲突检测,如果发现冲突,则回滚操作,重新尝试。乐观锁的典型应用场景是 CAS(比较并交换)算法,以及 Java 中的 AtomicInteger 类和 LongAdder 类。乐观锁实现相对复杂,但能够提高并发性能,避免了加锁的开销。
总的来说,悲观锁适用于对数据一致性要求比较高的场景,而乐观锁适用于对数据一致性要求相对较低、并发度较高的场景。