MYSQL 作为开源数据库的明星,整体目前的无论从开发还是DBA,人才比较卷,已经到了一定的地步,偶然刷抖音,刷到一个面试的视频,面试一个MYSQL开发的程序小哥,面试人连珠炮的MYSQL 灵魂问题冲向小哥,现在就来捋一捋,一个20K的程序员要掌握的MYSQL的知识有哪些。
一上来面试的人提出如下问题,没有任何停歇
1 什么是事务,你对事物是怎么理解的?
2 事务的四大特性是怎么理解的,隔离级别是什么,有哪几种隔离级别
3 你对MYSQL的锁有什么理解,MYSQL的锁有几种
4 MYSQL的行锁,锁的是行记录还是索引 ?
5 你怎么理解MYSQL的行锁,间隙锁,表锁的,在什么时候用什么样的锁 ?
6 当前读还有快照读,代表什么意思,举例在什么时候用什么样的读?
7 一条SQL 语句的执行的流程
8 WAL 的机制了解吗?
9 MVCC 的原理是什么
10 什么是聚簇索引,什么是普通索引,他们的结构是怎么样的
11 什么是回表,什么是索引失效
12 什么是UNDO LOG ,REDO LOG ,ERROR LOG ,BINLOG 分别解决什么问题?
注意以上是考一个程序开发人员,和DBA 没有半毛钱关系?如果你是DBA 你可以将这些问题,一次性回答出来吗?
下面尝试将锁的问题进行回答,主要的原因还是这些问题问到我,我也不确定能否完整的答上来。
首先为什么要有锁,锁的由来比较复杂,主要来自于以下几个部分
1 并发,基于数据库的访问都是多用户的模式,多用户在访问同一个资源的时候,必然会产生冲突,其中一部分通过了 MVCC 多版本控制来解决,而另一部分就需要通过锁来解决。
2 并发中主要有三种情况,多个线程同时读一个资源, 同时多个线程读,写一个资源,多个线程同时写一个资源。
其中出现问题的主要在两个点
1 读 和 写, 读写可能出现脏读和幻读,以及不可重复读的场景,这里面我们需要通过隔离级别来去解决其中的部分问题。
2 写 和 写 ,同时更新数据会导致更新同一个资源的数据导致逻辑错误以及数据丢失的问题。
基于并发控制中,处理的方式也主要有三种
1 悲观并发:先加锁,后访问的策略
2 乐观并发: 先访问,后检测的策略
3 多版本并发:每个写操作创建新的版本,读操作根据可见性的原则访问其中的一个快照
实际上我们目前整体大多数数据库已经使用了多版本的并发的方式来处理数据库的并发访问的问题, 传统我们认为隔离级别是 4个
1 read uncommitted
2 read committed
3 repeatable read
4 Serializable
其实根据后续的眼神我们产生了更多的细化的隔离级别的变种, 第五种snapshot 就是其中的一个门类。具体想了解这个隔离级别可以看下面的位置
https://cloud.tencent.com/developer/article/1847730
总的来说snapshot 隔离级别解决了事务隔离级别和性能之间的矛盾问题,有效的提高了数据库并发的性能问题。
说到MYSQL 的锁的问题,MYSQL 的锁主要分为3个级别
1 DB级别, 全局锁
2 表级别, MDL 锁 表锁
3 行级别, next-key lock , grap lock , record lock
1 全局锁, 全局锁在添加锁后,数据库处于只读状态,对数据的增删改以及DDL 处于阻塞的状态。加锁方式 lock flush table with read lock 解锁的方式 unlock tables
2 表级锁,表级锁包含对同一个表操作的锁级别的操作,其中分为表共享锁,和表独占锁,共享锁主要针对写进行阻塞, 而表独占锁对同一个表的读写都阻塞。加锁的方式 lock tables table_name read/write ,释放锁 unlock table table_name
3 MDL锁,主要面对的两种情况 DML 操作和 DDL 操作,在进行DML 操作时,DML 操作可以并发进行,但是DDL 操作将被阻塞, 而DDL 操作则要进入独占锁的模式,一个时刻只能有一个DDL 工作。
4 行级别主要有四种锁, S , X , IS , IX
在操作中,select 不加锁,通过查询特定的snapshot 来进行数据的给出,DML 操作在行加排它锁。
在上面有一个问题,关于加锁是在哪里加的问题,针对这个问题,加锁是在数据的索引中加锁的,在查询中是有相关的条件的,查询条件就有相关的索引建立的必要性,也就是二级索引,在更新数据的时候,针对索引条件中的索引项进行加锁,对于聚集索引也就是MYSQL 的主键,如果通过主键查询,则对主键进行加锁的操作。
这里就涉及锁的类型了
1 record lock 这里主要对索引记录想进行加锁
2 Gap lock 对索引之间的间隙加锁,加锁后,形成一个范围,范围内不允许插入记录,主要是在 repeatable read 中防止幻读
3 next-key lock ,通过这个锁的加锁主要针对索引有几种加锁的方式
1 唯一值,等值, 针对索引项存在是,next-key lock 退化为 record lock
2 唯一索引范围查询,加锁到不满足条件的第一个记录的索引为止
3 非唯一索引,通过next-key lock ,加锁,直到不满足条件的第一个值后next-key lock 变为 gap lock
4 非唯一索引范围查询,访问到不满足条件的第一个值为止
到此为止,对于关于MYSQL 的锁的问题,如果要问我的时候,到这个程度,稍微有一些底了。
另外附上,查询MYSQL 锁
1 查询BLock 的情况
SELECT r.trx_id,
waiting_trx_id,
r.trx_mysql_thread_id
waiting_thread,
r.trx_query
waiting_query,
b.trx_id,
blocking_trx_id,
b.trx_mysql_thread_id,
blocking_thread,
b.trx_query,
blocking_query
FROM performance_schema.data_lock_waits w
INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_engine_transaction_idINNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_engine_transaction_id;
2 查询锁等待的情况
SELECT
waiting_trx_id,
waiting_pid,
waiting_query,
blocking_trx_id,
blocking_pid,
blocking_query
FROM sys.innodb_lock_waits;
基于MYSQL 的这部分暂时到此为止,不过基于MYSQL 的卷,可从不曾停止。