本文已参与「新人创作礼」活动,一起开启掘金创作之路。
锁
MySQL 锁机制
- 当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制
锁类别上来分 MySQL 有哪些锁
- 共享锁:又叫读锁
- 排他锁:数据写入时,对数据加上排他锁;排他锁也称作独占锁,在某一时刻只能被一个线程占有,其他线程必须等待锁被释放之后才可能获取到锁;排他锁只能加一个,与其他排他锁及共享锁都互斥
隔离级别与锁的关系
- 在读未提交级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突
- 在读已提交级别下,读操作需要加共享锁,语句执行完以后会释放共享锁
- 在可重复读级别下,读操作需要加共享锁,在事务提交以后才释放共享锁
- 在串行化级别下,该级别锁定整个范围的键,并一直持有锁,直到事务完成
按照锁的粒度来分数据库锁有哪些
-
行级锁
- 是 MySQL 中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁
- 加锁粒度最小,开销最大,会出现死锁,锁冲突概率低,并发度最高
-
表级锁
- 是MySQL 中锁定粒度最大的一种锁,表示对当前操作的整张表加锁
- 实现简单,资源消耗较少,MyISAM 与 InnoDB 都支持表级锁
- 开销小,加锁快,不会出现死锁,锁定粒度大,锁冲突概率最高,并发度最低
-
页级锁
- 是 MySQL 中锁定粒度介于行锁和表锁中间的一种锁
- 会出现死锁,并发度一般,开销和锁定粒度介于表锁和行锁之间
MySQL 中 InnoDB 引擎的行锁如何实现
- 基于索引完成行锁
- 例:select * from table_name where id = 23 for update, for upate 可根据查询条件完成行锁锁定,并且id 是有索引键的列
- 如果 id 不是索引键那么 InnoDB 将完成表锁,并发就没有了
InnoDB 存储引擎的锁算法
- Record lock:单个行记录上的锁
- Gap lock:间隙锁,锁定一个范围,但不包括记录本身,会导致幻读产生
- Next-key lock:上面两种的结合,锁定一个范围,包括记录本身(对行的查询使用)
- 当查询的索引含有唯一属性时,next-key lock 降级为 record lock
什么时死锁,如何解决
- 死锁是指多个事务在同一资源上相互占用,并请求锁定对方的资源,导致恶性循环
- 解决:分布式事务锁或者乐观锁
乐观锁和悲观锁
-
乐观锁:假设不会发生并发冲突,只是在提交操作时检查是否违反数据完整性;在修改数据的时候把事务锁起来,通过 version 的方式来进行锁定;实现方式一般为版本号机制或 CAS 算法实现
-
悲观锁:假定会发生并发冲突,在查询完数据的时候就把事务锁起来,知道提交事务;实现方式为数据库中的锁机制
for update -
使用场景
- 乐观锁适用于读多写少的场景,也是一般项目中的大多数场景
- 多写的场景下可以用悲观锁
-
END -