面试_Mysql
Mysql的常见面试题
NULL 和 ‘’ 的区别是什么?(4点)
NULL
跟 ''
(空字符串)是两个完全不一样的值,区别如下:
NULL
代表一个不确定的值,就算是两个NULL
,它俩也不一定相等。例如,SELECT NULL=NULL
的结果为 false,但是在我们使用DISTINCT
,GROUP BY
,ORDER BY
时,NULL
又被认为是相等的。''
的长度是 0,是不占用空间的,而NULL
是需要占用空间的。NULL
会影响聚合函数的结果。例如,SUM
、AVG
、MIN
、MAX
等聚合函数会忽略NULL
值。COUNT
的处理方式取决于参数的类型。如果参数是*
(COUNT(*)
),则会统计所有的记录数,包括NULL
值;如果参数是某个字段名(COUNT(列名)
),则会忽略NULL
值,只统计非空值的个数。- 查询
NULL
值时,必须使用IS NULL
或IS NOT NULLl
来判断,而不能使用 =、!=、 <、> 之类的比较运算符。而''
是可以使用这些比较运算符的。
MySQL 不建议使用 NULL 作为列的默认值,主要有以下几个原因:(三点)
- 存储效率:NULL 值在数据库中的存储需要额外的空间和处理,因为它不同于其他普通值。这可能会导致数据库的存储效率降低。
- 查询复杂性:当在查询中处理 NULL 值时,需要使用特殊的语法,如**
IS NULL
或IS NOT NULL
条件**。这增加了查询的复杂性,并可能使查询逻辑变得复杂且容易出错。 - 数据质量:NULL 值通常表示未知或不确定的数据,
NULL
代表一个不确定的值,就算是两个NULL
,它俩也不一定相等。例如,SELECT NULL=NULL
的结果为 false,但是在我们使用DISTINCT
,GROUP BY
,ORDER BY
时,NULL
又被认为是相等的。
Boolean 类型如何表示?
MySQL 中没有专门的布尔类型,而是用 TINYINT(1) 类型来表示布尔值。TINYINT(1) 类型可以存储 0 或 1,分别对应 false 或 true。
存储引擎
MySQL 支持哪些存储引擎?默认使用哪个?
MySQL 支持多种存储引擎,你可以通过 SHOW ENGINES
命令来查看 MySQL 支持的所有存储引擎。
从上图我们可以查看出, MySQL 当前默认的存储引擎是 InnoDB。并且,所有的存储引擎中只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。
MySQL 存储引擎架构了解吗
MySQL 存储引擎采用的是 插件式架构 ,支持多种存储引擎,我们甚至可以为不同的数据库表设置不同的存储引擎以适应不同场景的需要。存储引擎是基于表的,而不是数据库。
并且,你还可以根据 MySQL 定义的存储引擎实现标准接口来编写一个属于自己的存储引擎。这些非官方提供的存储引擎可以称为第三方存储引擎,区别于官方存储引擎。像目前最常用的 InnoDB 其实刚开始就是一个第三方存储引擎,后面由于过于优秀,其被 Oracle 直接收购
MyISAM 和 InnoDB 有什么区别?(五点)
MySQL 5.5 之前,MyISAM 引擎是 MySQL 的默认存储引擎,可谓是风光一时。
两者的对比:
1.是否⽀持⾏级锁 : MyISAM 只有表级锁(table-level locking),⽽InnoDB ⽀持⾏级锁(rowlevel locking)和表级锁,默认为⾏级锁。
是否⽀持事务和崩溃后的安全恢复: MyISAM 强调的是性能,每次查询具有原⼦性,其执⾏ 速度⽐InnoDB类型更快,但是不提供事务⽀持。但是InnoDB 提供事务⽀持事务,外部键等 ⾼级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能⼒(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。(relog)
是否⽀持外键: MyISAM不⽀持,⽽InnoDB⽀持。
**是否⽀持MVCC **:仅 InnoDB ⽀持。应对⾼并发事务, MVCC⽐单纯的加锁更⾼效;MVCC只 在 READ COMMITTED 和 REPEATABLE READ 两个隔离级别下⼯作;MVCC可以使⽤ 乐 观(optimistic)锁 和 悲观(pessimistic)锁来实现;各数据库中MVCC实现并不统⼀。
InnoDB 的性能比 MyISAM 更强大
日志
MySQL日志:常见的日志都有什么用?
MySQL中常见的日志类型主要有下面几类(针对的是InnoDB存储引擎)∶·
- 错误日志(error log) :对MySQL的启动、运行、关闭过程进行了记录。
- 二进制日志(binary log):主要记录的是更改数据库数据的SQL语句。(bin log)
- 一般查询日志(general query log):已建立连接的客户端发送给MySQL服务器的所有SQL记录,因为SQL的量比较大,默认是不开启的,也不建议开启。
- **慢查询日志(slow query log)**︰执行时间超过long_query_time秒钟的查询,解决SQL慢查询问题的时候会用到。
- **事务日志(redo log 和undo log) **: redo log 是重做日志,undo log是回滚日志。
二进制日志 binlog(归档日志)和事务日志(redo log和undo log)比较重要,需要我们重点关注。
慢查询日志
在实际项目中,慢查询日志可能会比较大,直接分析的话不太方便,我们可以借助MySQL官方的慢查询分析调优工具mysqldumpslow。
binLog日志
MysQL binlog(binary log即二进制日志文件)用于记录数据库中所有的数据更改操作。Binlog的主要作用包括数据恢复、数据备份、数据同步和复制等场景。 MySQL 数据库的数据备份、主备、主主、主从都离不开 binlog
Binlog的工作原理主要涉及三个方面:事件写入、日志刷新和日志索引。当一个事务被提交时,MySQL会将该事务的所有修改操作作为一个事件写入到binlog中。然后,MySQL会定期地将内存中的binlog缓存刷新到磁盘上的binlog文件中。此外,MySQL还会维护一个binlog索引文件,记录所有的binlog文件列表。
binlog通过追加的方式进行写入,大小没有限制。并且,我们可以通过max_binlog_size
参数设置每个binlog文件的最大容量,当文件大小达到给定值之后,会生成新的binlog文件来保存日志,不会出现前面写的日志被覆盖的情况。
宕机了怎么办?
redo log
redo log(重做日志)是 InnoDB 存储引擎独有的,它让 MySQL 拥有了崩溃恢复能力。
比如 MySQL 实例挂了或宕机了,重启时,InnoDB 存储引擎会使用 redo log 恢复数据,保证数据的持久性与完整性。
MySQL 中数据是以页为单位,你查询一条记录,会从硬盘把一页的数据加载出来,加载出来的数据叫数据页,会放入到 Buffer Pool
中。Buffer Pool是存储引擎中的缓存。
后续的查询都是先从 Buffer Pool
中找,没有命中再去硬盘加载,减少硬盘 IO 开销,提升性能。
更新表数据的时候,也是如此,发现 Buffer Pool
里存在要更新的数据,就直接在 Buffer Pool
里更新。
然后会把“在某个数据页上做了什么修改”记录到重做日志缓存(redo log buffer
)里,接着刷盘到 redo log 文件里。
InnoDB 将 redo log 刷到磁盘上有几种情况(说出四点):
- 事务提交:当事务提交时,log buffer 里的 redo log 会被刷新到磁盘(可以通过
innodb_flush_log_at_trx_commit
参数控制,后文会提到)。 - log buffer 空间不足时:log buffer 中缓存的 redo log 已经占满了 log buffer 总容量的大约一半左右,就需要把这些日志刷新到磁盘上。
- 事务日志缓冲区满:InnoDB 使用一个事务日志缓冲区(transaction log buffer)来暂时存储事务的重做日志条目。当缓冲区满时,会触发日志的刷新,将日志写入磁盘。
- Checkpoint(检查点,时间点):InnoDB 定期会执行检查点操作,将内存中的脏数据(已修改但尚未写入磁盘的数据)刷新到磁盘,并且会将相应的重做日志一同刷新,以确保数据的一致性。
- 后台刷新线程:InnoDB 启动了一个后台线程,负责周期性(每隔 1 秒)地将脏页(已修改但尚未写入磁盘的数据页)刷新到磁盘,并将相关的重做日志一同刷新。
- 正常关闭服务器:MySQL 关闭的时候,redo log 都会刷入到磁盘里去。
redo log 如何保证事务的持久性?
持久性,一个事务提交之后,他对数据库的修改是永久的,就算数据库发生宕机也不应该改变。
我们知道InnoDB存储引擎是以页为单位来管理存储空间的,我们往MySQL插入的数据最终都是存在于页中的,准确点来说是数据页这种类型。为了减少磁盘IO开销,还有一个叫做Buffer Pool(缓冲池的区域,存在于内存中。当我们的数据对应的页不存在于Buffer Pool 中的话,MySQL 会先将磁盘上的页缓存到Buffer Pool中,这样后面我们直接操作的就是Buffer Pool 中的页,这样大大提高了读写性能。
一个事务提交之后,我们对 Buffer Pool中对应的页的修改可能还未持久化到磁盘。这个时候,如果MySQL突然宕机的话,这个事务的更改是不是直接就消失了呢?
很显然是不会的,如果是这样的话就明显违反了事务的持久性。
MysQL InnoDB引擎使用redo log来保证事务的持久性。redo log主要做的事情就是记录页的修改,比如某个页面某个偏移量处修改了几个字节的值以及具体被修改的内容是什么。redo log 中的每一条记录包含了表空间号、数据页号、偏移量、具体修改的数据,甚至还可能会记录修改数据的长度(取决于redo log类型)。
在事务提交时,我们会将redo log按照刷盘策略刷到磁盘上去,这样即使MySQL宕机了,重启之后也能恢复未能写入磁盘的数据,从而保证事务的持久性。也就是说,redo log让MySQL具备了崩溃回复能力。
不过,我们也要注意设置正确的刷盘策略innodb_flush_log_at_trx_commit
,根据MySQL配置的刷盘策略的不同,MySQL宕机之后可能会存在轻微的数据丢失问题。
刷盘策略innodb_flush_log_at_trx_commit
的默认值为1,设置为1的时候才不会丢失任何数据。为了保证事务的持久性,我们必须将其设置为1。1表示每次事务提交时都将进行刷盘操作。这种方式性能最低,但是也最安全,因为只要事务提交成功,redo log 记录就一定在磁盘里,不会有任何数据丢失。
页修改之后为什么不直接刷盘(不使用redo log,在缓存修改之后,马上去刷盘)
实际上,数据页大小是16KB
,刷盘比较耗时,可能就修改了数据页里的几 Byte
数据,有必要把完整的数据页刷盘吗?
而且数据页刷盘是随机写,因为一个数据页对应的位置可能在硬盘文件的随机位置,所以性能是很差。
如果是写 redo log,一行记录可能就占几十 Byte
,只包含表空间号、数据页号、磁盘文件偏移
量、更新值,再加上是顺序写,所以刷盘速度很快。
所以用 redo log 形式记录修改内容,性能会远远超过刷数据页的方式,这也让数据库的并发能力更强。
binlog和redolog有什么区别?(五点)
- binlog主要用于数据库还原,数据库备份,属于数据级别的数据恢复,主从复制是binlog最常见的一个应用场景。
- redolog主要用于保证事务的持久性,属于事务级别的数据恢复。
- redolog属于InnoDB引擎特有的,binlog属于所有存储引擎共有的,因为 binlog是 MySQL的Server层实现的。
- redolog 属于物理日志,主要记录的是某个页的修改。binlog属于逻辑日志,主要记录的是数据库执行的所有DDL和DML语句。
- binlog通过追加的方式进行写入,大小没有限制。redo log 采用循环写的方式进行写入,大小固定,当写到结尾时,会回到开头循环写日志。(会被覆盖)
逻辑日志:记录的语句
物理日志:记录修改的详细信息
undo log如何保证事务的原子性?
每一个事务对数据的修改都会被记录到undo log,当执行事务过程中出现错误或者需要执行回滚操作的话,MySQL可以利用undo log 将数据恢复到事务开始之前的状态。
undo log属于逻辑日志,记录的是SQL语句,比如说事务执行一条DELETE
语句,那undo log就会记录一条相对应的INSERT
语句。
relog 的两阶段提交?
在mysql进行更新操作的时候,需要将这次操作记录在relog和binlog两个日志当中去。这就涉及到一个问题,如果relog先提交,但是在binlog还没提交之前,mysql宕机了。那么binlog的数据就和relog不一致了。同理,binlog先提交也会出现这个问题。
所以,relog两阶段提交就出现了。也就是更新操作后,记录 redo log,此时 redo log 进入 prepare 状态,然后告诉执行器,执行完成了,随时可以提交。执行器收到通知后记录 binlog,然后调用引擎接口,提交 redo log 为提交状态。如果这个过程发生崩溃的情况,要进行恢复操作,只要relog不是处于commit阶段,那么只要去判断binlog是不是存在,如果存在,就直接提交relog,如果不存在,那就回滚。
我们验证一下,假设relog处在prepare状态,要提交binlog的时候发生了崩溃。那么这个时候binlog不存在,就是回滚。并且binlog和relog都没提交。显然这是正确的。如果写完了binlog,要提交relog的时候发生崩溃。那么这个时候binlog存在,直接提交relog就行。这个时候binlog和relog都提交了,数据也保持一致。这也是正确的。
事务
何为事务? 一言蔽之,事务是逻辑上的一组操作,要么都执行,要么都不执行。
事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账 1000 元,这个转账会涉及到两个关键操作,这两个操作必须都成功或者都失败。
- 将小明的余额减少 1000 元
- 将小红的余额增加 1000 元。
事务会把这两个操作就可以看成逻辑上的一个整体,这个整体包含的操作要么都成功,要么都要失败。这样就不会出现小明余额减少而小红的余额却并没有增加的情况。
事务的四大特性
原子性(Atomicity
):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
一致性(Consistency
):执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;
隔离性(Isolation
):并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
持久性(Durability
):一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
并发事务带来了哪些问题?
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对同一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。
- 脏读(Dirty read)当一个事务访问了一个数据数据并且对数据进行了修改,而这个修改还没有提交到数据库中。(这个修改对其他事务来说是可见的)。这时另外一个事务也访问了了这个数据,但第一个事务突然回滚,导致数据并没有被提交到数据库,那第二个事务读取到的就是脏数据,这也就是脏读的由来。
例如:事务 1 读取某表中的数据 A=20,事务 1 修改 A=A-1,事务 2 读取到 A = 19,事务 1 回滚导致对 A 的修改并未提交到数据库, A 的值还是 20。
- 丢失修改(Lost to modify)当一个事务访问一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。(同时)
例如:事务 1 读取某表中的数据 A=20,事务 2 也读取 A=20,事务 1 先修改 A=A-1,事务 2 后来也修改 A=A-1,最终结果 A=19,事务 1 的修改被丢失。
- 不可重复读(Unrepeatable read)指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
例如:事务 1 读取某表中的数据 A=20,事务 2 也读取 A=20,事务 1 修改 A=A-1,事务 2 再次读取 A =19,此时读取的结果和第一次读取的结果不同。
- 幻读(Phantom read)幻读与不可重复读类似。它发生在一个事务内读取了几行数据,接着另一个并发事务插入了一些数据时。在随后的查询中,第一个事务就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读
不可重复读和幻读有什么区别?
- 不可重复读的重点是内容修改或者记录减少比如多次读取一条记录发现其中某些记录的值被修改;
- 幻读的重点在于记录新增比如多次执行同一条查询语句(DQL)时,发现查到的记录增加了
并发事务的控制方式有哪些?
MySQL 中并发事务的控制方式无非就两种:锁 和 MVCC。锁可以看作是悲观控制的模式,多版本并发控制(MVCC,Multiversion concurrency control)可以看作是乐观控制的模式。
1.锁 控制方式下会通过锁来显式控制共享资源而不是通过调度手段,MySQL 中主要是通过 读写锁 来实现并发控制。
- 共享锁(S 锁):又称读锁,事务在读取记录的时候获取共享锁,允许多个事务同时获取(锁兼容)。
- 排他锁(X 锁):又称写锁/独占锁,事务在修改记录的时候获取排他锁,不允许多个事务同时获取。如果一个记录已经被加了排他锁,那其他事务不能再对这条记录加任何类型的锁(锁不兼容)。
读写锁可以做到读读并行,但是无法做到写读、写写并行。另外,根据根据锁粒度的不同,又被分为 表级锁(table-level locking) 和 行级锁(row-level locking) 。InnoDB 不光支持表级锁,还支持行级锁,默认为行级锁。行级锁的粒度更小,仅对相关的记录上锁即可(对一行或者多行记录加锁),所以对于并发写入操作来说, InnoDB 的性能更高。不论是表级锁还是行级锁,都存在共享锁(Share Lock,S 锁)和排他锁(Exclusive Lock,X 锁)这两类。
2.MVCC 是多版本并发控制方法,即对一份数据会存储多个版本,通过事务的可见性来保证事务能看到自己应该看到的版本。通常会有一个全局的版本分配器来为每一行数据设置版本号,版本号是唯一的。(使用了隐藏字段)
MVCC 在 MySQL 中实现所依赖的手段主要是: 隐藏字段、read view、undo log。
- undo log : undo log 用于记录某行数据的多个版本的数据。
- read view 和 隐藏字段 : 用来判断当前版本数据的可见性。
说说你对MVCC的了解
MVCC 是多版本并发控制方法,可以看做是一种乐观控制,即对一份数据会存储多个版本,通过事务的可见性来保证事务能看到自己应该看到的版本。通常会有一个全局的版本分配器来为每一行数据设置版本号,版本号是唯一的。(使用了隐藏字段),其主要目的是允许多个用户同时访问数据库,而不会导致数据冲突和不一致性。
MVCC的工作原理大致如下:
- 每个事务在启动时,系统会为其分配一个唯一的事务ID。
- 当一个事务要访问数据库中的某个数据时,系统会检查该数据的版本号和事务的启动时间。如果该数据的版本号(时间戳)早于该事务的启动时间,则该事务可以访问该数据;否则,该事务需要等待其他事务完成对该数据的访问。
- 当一个事务修改某个数据时,系统会为该数据创建一个新版本号,并将修改后的数据存储在一个新的位置。同时,旧版本的数据仍然可用供其他事务访问。
- 当一个事务提交时,系统会将其所做的所有修改操作都合并到数据库中,同时删除旧版本的数据。
MVCC主要用于Read Committed和Repeatable Read这两个隔离级别,MVCC可以确保每个事务都读取到它开始时的数据状态。读取未提交不需要控制,而串行化一般通过加锁
SQL 标准定义了哪些事务隔离级别?
SERIALIZABLE
隔离级别是通过锁来实现的,READ-COMMITTED
和 REPEATABLE-READ
隔离级别是基于 MVCC 实现的。不过, SERIALIZABLE 之外的其他隔离级别可能也需要用到锁机制,就比如 REPEATABLE-READ
在当前读情况下需要使用加锁读来保证不会出现
SQL 标准定义了四个隔离级别:
- READ-UNCOMMITTED(读取未提交) :最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- READ-COMMITTED(读取已提交) :只允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读) :对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- SERIALIZABLE(可串行化) :最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITTED | × | √ | √ |
REPEATABLE-READ | × | × | √ |
SERIALIZABLE | × | × | × |
这⾥需要注意的是:
与 SQL 标准不同的地⽅在于 InnoDB 存储引擎在 REPEATABLEREAD(可重读)事务隔离级别下使⽤的是Next-Key Lock 锁算法,因此可以避免幻读的产⽣,这与其他数据库系 统(如 SQL Server) 是不同的。
所以说InnoDB 存储引擎的默认⽀持的隔离级别是 REPEATABLE-READ(可重读) 已经可以完全保证事务的隔离性要求,即达到了 SQL标准的 SERIALIZABLE(可串⾏化) 隔离级别。
因为隔离级别越低,事务请求的锁越少,所 以⼤部分数据库系统的隔离级别都是 READ-COMMITTED(读取提交内容) ,但是你要知道的是 InnoDB 存储引擎默认使⽤ REPEAaTABLE-READ(可重读) 并不会有任何性能损失。 InnoDB 存储引擎在 分布式事务 的情况下⼀般会⽤到 SERIALIZABLE(可串⾏化) 隔离级别。
Mysql的锁
表级锁和行级锁了解吗?有什么区别?
MyISAM 仅仅支持表级锁(table-level locking),一锁就锁整张表,这在并发写的情况下性非常差。InnoDB 不光支持表级锁(table-level locking),还支持行级锁(row-level locking),默认为行级锁。
行级锁的粒度更小,仅对相关的记录上锁即可(对一行或者多行记录加锁),所以对于并发写入操作来说, InnoDB 的性能更高。
表级锁和行级锁对比:
- 表级锁: MySQL 中锁定粒度最大的一种锁(全局锁除外),是针对非索引字段加的锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。不过,触发锁冲突的概率最高,高并发下效率极低。表级锁和存储引擎无关,MyISAM 和 InnoDB 引擎都支持表级锁。
- 行级锁: MySQL 中锁定粒度最小的一种锁,是 针对索引字段加的锁 ,只针对当前操作的行记录进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。行级锁和存储引擎有关,是在存储引擎层面实现的。
InnoDB 有哪几类行锁?
InnoDB 行锁是通过对索引数据页上的记录加锁实现的,MySQL InnoDB 支持三种行锁定方式:
- 记录锁(Record Lock):也被称为记录锁,属于单个行记录上的锁。
- 间隙锁(Gap Lock):锁定一个范围,不包括记录本身。
- 临键锁(Next-Key Lock):Record Lock+Gap Lock,锁定一个范围,包含记录本身,主要目的是为了解决幻读问题(MySQL 事务部分提到过)。记录锁只能锁住已经存在的记录,为了避免插入新记录,需要依赖间隙锁。
在 InnoDB 默认的隔离级别 REPEATABLE-READ 下,行锁默认使用的是 Next-Key Lock。但是,如果操作的索引是唯一索引或主键,InnoDB 会对 Next-Key Lock 进行优化,将其降级为 Record Lock,即仅锁住索引本身,而不是范围。
共享锁和排他锁呢?
不论是表级锁还是行级锁,都存在共享锁(Share Lock,S 锁)和排他锁(Exclusive Lock,X 锁)这两类:
- 共享锁(S 锁):又称读锁,事务在读取记录的时候获取共享锁,允许多个事务同时获取(锁兼容)。
- 排他锁(X 锁):又称写锁/独占锁,事务在修改记录的时候获取排他锁,不允许多个事务同时获取。如果一个记录已经被加了排他锁,那其他事务不能再对这条事务加任何类型的锁(锁不兼容)。
意向锁有什么作用?
如果需要用到表锁的话,如何判断表中的记录没有行锁呢,一行一行遍历肯定是不行,性能太差。我们需要用到一个叫做意向锁的东东来快速判断是否可以对某个表使用表锁。
意向锁是表级锁,共有两种:
- 意向共享锁(Intention Shared Lock,IS 锁):事务有意向对表中的某些记录加共享锁(S 锁),加共享锁前必须先取得该表的 IS 锁。
- 意向排他锁(Intention Exclusive Lock,IX 锁):事务有意向对表中的某些记录加排他锁(X 锁),加排他锁之前必须先取得该表的 IX 锁。
意向锁是由数据引擎自己维护的,用户无法手动操作意向锁,在为数据行加共享/排他锁之前,InooDB 会先获取该数据行所在在数据表的对应意向锁。·
意向锁之间是互相兼容的。
IS 锁 | IX 锁 | |
---|---|---|
IS 锁 | 兼容 | 兼容 |
IX 锁 | 兼容 | 兼容 |
意向锁和共享锁和排它锁互斥(这里指的是表级别的共享锁和排他锁,意向锁不会与行级的共享锁和排他锁互斥)。
IS 锁 | IX 锁 | |
---|---|---|
S 锁 | 兼容 | 互斥 |
X 锁 | 互斥 | 互斥 |
具体来说,当有事务给表的数据行加了共享锁或排他锁时,同时会给表设置一个标识,这个标识就是意向锁,代表已经有行锁了。其他事务要想对表加表锁时,就不必逐行判断有没有行锁可能与表锁冲突,直接读这个标识就可以确定自己该不该加表锁。