共计 3354 个字符,预计需要花费 9 分钟才能阅读完成。
图片: https://uploader.shimo.im/f/y…
往期文章举荐
- mysql 那些事儿 | 深入浅出 mysql 索引(上)
- mysql 那些事儿 | 深入浅出 mysql 索引(下)
- 为什么 Mysql 用 B + 树做索引而不必 B - 树或红黑树?
- mysql 那些事儿 |mysql 事务隔离机制及其原理
- 校招 mysql 那些事儿 | 日志模块 binlog/redolog/undolog
- 校招 mysql 那些事 |MVCC 原理机制
- mysql 那些事儿 |mysql 锁总结
目录
- 锁定义
- 锁分类
- 读锁和写锁
- 表锁和行锁
- InnoDB 共享锁和排他锁
- InnoDB 意向锁和排他锁
- InnoDB 行锁
-
InnoDB 间隙锁
- 概念
- InnoDB 应用间隙锁目标
- InnoDB 行锁实现形式
- 闲聊
- 欢送退出我的公众号【迈莫 coding】一起 pk 大厂
锁定义
锁是计算机协调多个过程或线程并发拜访某一资源的机制。
在数据库中,除了传统的计算资源 (如 CPU, RAM, I/ O 等) 的争用以外,数据也是一种供须要用户共享的资源。锁抵触也是影响数据库并发拜访性能的一个重要因素。
锁分类
- 从性能上分为乐观锁 (用版本比照来实现) 和乐观锁
- 从数据库操作的类型分为读锁和写锁(都属于乐观锁)
- 从对数据操作的粒度分:分为表锁和行锁
读锁和写锁
- 读锁(共享锁):针对同一份数据,多个读操作能够同时进行而不会相互影响,然而会阻塞写操作
- 写锁(互斥锁):以后写操作没有实现前,它会阻断其余写锁和读锁
表锁和行锁
表锁
- 每次操作时会锁住整张表。开销小,加锁快;不会产生死锁;锁定粒度大,产生锁抵触的概率最高;并发度最低;
- 表锁更适宜于以查问为主,并发用户少,只有大量按索引条件更新数据的利用,如 Web 利用
行锁
- 每次操作锁住一行数据。开销大,加锁慢;会呈现死锁;锁定粒度最小,产生锁抵触的概率最低;并发度最高;
- 行级锁只在存储引擎层实现,而 mysql 服务器没有实现。
- 行级锁更适宜于有大量按索引条件并发更新大量不同数据,同时又有并发查问的利用,如一些 - 在线事务处理 (OLTP) 零碎
InnoDB 共享锁和排他锁
InnoDB 实现了两种类型的行锁:
- 共享锁(S): 容许一个事务去读一行,阻止其余事务取得雷同数据集的排他锁
- 排他锁(X): 容许取得排他锁的事务更新数据,阻止其余事务获得雷同数据集的共享读锁和排他写锁
为了容许行锁和表锁共存,实现多粒度锁机制,InnoDB 还有两种外部应用的意向锁(Intention Locks),这两种意向锁都是表锁:
- 动向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先获得该表的 IS 锁
- 动向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先获得该表的 IX 锁
InnoDB 意向锁和排他锁
- 意向锁是 InnoDB 引擎主动加的,不须要用户干涉
- 对于
UPDATE
INSERT
DELETE
语句,InnoDB 引擎会主动给波及数据集加排他锁(X) - 对于一般
SELECT
语句,InnoDB
不会加任何锁 -
事务能够通过以下语句显式地给后果集加共享锁或排它锁
- 共享锁(S):
SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
。其余 session 依然能够查问记录,并也能够对该记录加 share mode 的共享锁。然而如果以后事务须要对该记录进行更新操作,则很有可能造成死锁。 - 排它锁(X):
SELECT * FROM table_name WHERE ... FOR UPDATE
。其余 session 能够查问该记录,然而不能对该记录加共享锁或排他锁,而是期待取得锁
- 共享锁(S):
InnoDB 行锁
- innoDB 行锁通过索引上的索引项加锁来实现的,这一点 MySQL 与 Oracle 不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB 这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB 才应用行级锁,否则,InnoDB 将应用表锁!
- 不论是应用主键索引、惟一索引或一般索引,InnoDB 都会应用行锁来对数据加锁。
- 只有执行打算真正应用了索引,能力应用行锁:即使在条件中应用了索引字段,但是否应用索引来检索数据是由 MySQL 通过判断不同执行打算的代价来决定的,如果 MySQL 认为全表扫描效率更高,比方对一些很小的表,它就不会应用索引,这种状况下 InnoDB 将应用表锁,而不是行锁。
- 因为 MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以尽管多个 session 拜访不同行的记录,然而如果是应用雷同的索引键,是会呈现锁抵触的(后应用这些索引的 session 须要期待先应用索引的 session 开释锁后,能力获取锁)。利用设计的时候要留神这一点。
InnoDB 间隙锁
概念
当咱们用范畴条件而不是相等条件检索数据,并申请共享或排他锁时,InnoDB 会给符合条件的已有数据记录的索引项加锁;对于键值在条件范畴内但并不存在的记录,叫做“间隙(GAP)”,InnoDB 也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key 锁)。
很显然,在应用范畴条件检索并锁定记录时,InnoDB 这种加锁机制会阻塞符合条件范畴内键值的并发插入,这往往会造成重大的锁期待。因而,在理论利用开发中,尤其是并发插入比拟多的利用,咱们要尽量优化业务逻辑,尽量应用相等条件来拜访更新数据,防止应用范畴条件。
InnoDB 应用间隙锁的目标:
- 避免幻读,以满足相干隔离级别的要求;满足复原和复制的须要
-
MySQL 通过 BINLOG 录入执行胜利的 INSERT、UPDATE、DELETE 等更新数据的 SQL 语句,并由此实现 MySQL 数据库的复原和主从复制。MySQL 的复原机制(复制其实就是在 Slave Mysql 一直做基于 BINLOG 的复原)有以下特点:
- 一是 MySQL 的复原是 SQL 语句级的,也就是从新执行 BINLOG 中的 SQL 语句。
- 二是 MySQL 的 Binlog 是依照事务提交的先后顺序记录的,复原也是按这个程序进行的。
由此可见,MySQL 的复原机制要求:在一个事务未提交前,其余并发事务不能插入满足其锁定条件的任何记录,也就是不容许呈现幻读。
InnoDB 加锁形式
– 隐式锁定:
InnoDB 在事务执行过程中,应用两阶段锁协定:
随时都能够执行锁定,InnoDB 会依据隔离级别在须要的时候主动加锁;
锁只有在执行 commit
或者 rollback
的时候才会开释,并且所有的锁都是在同一时刻被开释。
– 显式锁定:
select ... lock in share mode // 共享锁
select ... for update // 排他锁
– select for update:
在执行这个 select 查问语句的时候,会将对应的索引拜访条目进行上排他锁(X 锁),也就是说这个语句对应的锁就相当于 update 带来的成果。
– select for update 的应用场景*
为了让本人查到的数据确保是最新数据,并且查到后的数据只容许本人来批改的时候,须要用到 for update 子句。
– select lock in share mode
in share mode 子句的作用就是将查找到的数据加上一个 share 锁,这个就是示意其余的事务只能对这些数据进行简略的select
操作,并不可能进行 DML 操作。
– select lock in share mode 应用场景*
为了确保本人查到的数据没有被其余的事务正在批改,也就是说确保查到的数据是最新的数据,并且不容许其他人来批改数据。然而本人不肯定可能批改数据,因为有可能其余的事务也对这些数据 应用了 in share mode
的形式上了 S 锁。
– 性能影响
select for update
语句,相当于一个update
语句。在业务忙碌的状况下,如果事务没有及时的 commit 或者 rollback 可能会造成其余事务长时间的期待,从而影响数据库的并发应用效率。select lock in share mode
语句是一个给查找的数据上一个共享锁(S 锁)的性能,它容许其余的事务也对该数据上 S 锁,然而不可能容许对该数据进行批改。如果不及时的commit
或者rollback
也可能会造成大量的事务期待。
闲聊
- 读完文章,本人是不是和 mysql 锁的 cp 率又进步了
- 我是迈莫,欢送大家和我交换
文章也会继续更新,能够微信搜寻「迈莫 coding」第一工夫浏览。每天分享优质文章、大厂教训、大厂面经,助力面试,是每个程序员值得关注的平台。