MySQL复习笔记整理

目录

1、MySQL数据库架构

[1.1 基本架构](#1.1 基本架构)

[1.2 存储引擎对比](#1.2 存储引擎对比)

[1.3 InnoDB存储引擎](#1.3 InnoDB存储引擎)

2、MySQL的索引

[2.1 B+ Tree介绍](#2.1 B+ Tree介绍)

[2.2 索引的数据结构选择](#2.2 索引的数据结构选择)

[2.3 常见索引类型(经常记混呜呜呜)](#2.3 常见索引类型(经常记混呜呜呜))

[2.4 索引失效](#2.4 索引失效)

[2.5 索引优化](#2.5 索引优化)

[2.6 分库分表](#2.6 分库分表)

3、主从复制与读写分离

[3.1 主从复制](#3.1 主从复制)

[3.2 读写分离](#3.2 读写分离)

4、事务和锁

[4.1 ACID特性](#4.1 ACID特性)

[4.2 隔离级别和存在问题](#4.2 隔离级别和存在问题)

5、MVCC实现机制

[5.1 什么是MVCC](#5.1 什么是MVCC)

[5.2 MVCC带来的好处](#5.2 MVCC带来的好处)

[5.3 什么是当前读和快照读](#5.3 什么是当前读和快照读)

[5.4 MVCC 核心](#5.4 MVCC 核心)

[5.5 Redo log 和 undo log](#5.5 Redo log 和 undo log)

[5.6 ReadView机制](#5.6 ReadView机制)

[5.7 隔离级别RR判断可见性](#5.7 隔离级别RR判断可见性)

6、MySQL中的锁

[6.1 锁的分类和区别](#6.1 锁的分类和区别)

[6.2 InnoDB行锁怎么实现的](#6.2 InnoDB行锁怎么实现的)

[6.3 InnoDB 锁的算法有哪几种(都有哪些行锁?)](#6.3 InnoDB 锁的算法有哪几种(都有哪些行锁?))


1、MySQL数据库架构

1.1 基本架构

大体来说,MySQL 可以分为 Server 层和存储引擎层两部分。

  • Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
  • 存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。

1.2 存储引擎对比

  • InnoDB:InnoDB是MySQL 默认的事务型存储引擎,只有在需要它不支持的特性时,才考虑使用其它存储引擎。
    • 实现了四个标准的隔离级别(读未提交、读已提交、可重复读、串行化),默认级别是可重复读(REPEATABLE READ)。重点要考:在可重复读隔离级别下,通过多版本并发控制(MVCC)+ 间隙锁(Next-Key Locking)防止幻影读。
    • 主索引是聚簇索引,在索引中保存了数据,从而避免直接读取磁盘,因此对查询性能有很大的提升。
  • MyISAM:设计简单,数据以紧密格式存储。对于只读数据,或者表比较小、可以容忍修复操作,则依然可以使用它。
    • 提供了大量的特性,包括压缩表、空间数据索引等。
    • 不支持行级锁,只能对整张表加锁,读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操作的同时,也可以往表中插入新的记录,这被称为并发插入(CONCURRENT INSERT)。

InnoDB和MyISAM对比:

  • 事务:InnoDB是事务型的,而MyISAM不支持事务
  • 并发:InnoDB支持行级别锁,MyISAM只支持表级锁
  • 外键:InnoDB支持外键,MyISAM无
  • 备份: InnoDB 支持在线热备份,MyISAM无
  • 崩溃恢复: MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢
  • 其它特性: MyISAM 支持压缩表和空间数据索引

1.3 InnoDB存储引擎

MySQL5.5 版本开始,默认使用InnoDB存储引擎,它擅长事务处理,具有崩溃恢复特性,在日常开发中使用非常广泛。下面是InnoDB架构图,左侧为内存结构,右侧为磁盘结构:

在左侧的内存结构中,主要分为这么四大块儿: Buffer Pool、Change Buffer、Adaptive Hash Index、Log Buffer。 下来介绍一下这四个部分:

  1. Buffer Pool :InnoDB存储引擎基于磁盘文件存储,访问物理硬盘和在内存中进行访问,速度相差很大,为了尽可能弥补这两者之间的I/O效率的差值,就需要把经常使用的数据加载到缓冲池中,避免每次访问都进行磁盘I/O。
  2. Change Buffer:更改缓冲区(针对于非唯一二级索引页),在执行DML语句时,如果这些数据Page没有在Buffer Pool中,不会直接操作磁盘,而会将数据变更存在更改缓冲区 Change Buffer中,在未来数据被读取时,再将数据合并恢复到Buffer Pool中,再将合并后的数据刷新到磁盘中。
  3. Log Buffer:日志缓冲区,用来保存要写入到磁盘中的log日志数据(redo log 、undo log),默认大小为 16MB,日志缓冲区的日志会定期刷新到磁盘中。如果需要更新、插入或删除许多行的事务,增加日志缓冲区的大小可以节省磁盘 I/O。
  4. Adaptive Hash Index :自适应hash索引,用于优化对Buffer Pool数据的查询。MySQL的innoDB引擎中虽然没有直接支持hash索引,但是给我们提供了一个功能就是这个自适应hash索引,因为hash索引在进行等值匹配时,一般性能是要高于B+树的。

2、MySQL的索引

2.1 B+ Tree介绍

  • B Tree 指的是 Balance Tree,也就是平衡树。平衡树是一颗查找树,并且所有叶子节点位于同一层。
  • B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具有 B Tree 的平衡性,并且通过顺序访问指针来提高区间查询的性能。在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 keyi 和 keyi+1,且不为 null,则该指针指向节点的所有 key 大于等于 keyi 且小于等于 keyi+1。

2.2 索引的数据结构选择

众所周知MySQL索引底层使用的数据结构是B+树,那么查询性能也很好的哈希、红黑树、二叉树等数据结构为什么不是第一选择呢?

  1. 红黑树、二叉树索引相比:红黑树和二叉树随着数据量增加树高也会增加,而作为数据可的索引,每遍历一层就要进行一次磁盘的交互,所以树越高与磁盘交互次数也越多,相应的查询速度就会越慢。
  2. 哈希索引相比:哈希虽然快,非常快,但是失去了有序性,范围查询就是灾难,也无法排序与分组。
  3. B Tree相比:B Tree的每个节点都存放了数据,而B+ Tree内部节点只存关键字信息,真正的数据都放在叶子节点,那么内部节点就可以存储更多的其他数据。具体对比如下:
  • 更高的查询效率:由于B+树在磁盘预读方面的优势,相对于B树,在同样的节点数和磁盘I/O次数下,可以提供更高的查询效率。
  • 更适合范围查询:数据库中常见的范围查询操作,如BETWEEN和ORDER BY等操作,在B+树中执行更快。而在B树中,可能需要反复进行I/O操作才能获取到完整的结果集。
  • 更好的顺序访问性:B+树的叶子节点之间采用链表连接,可以按照顺序遍历叶子节点,提高区间查询的性能。而B树则无法直接进行顺序遍历。
  • 更适合磁盘存储:数据库通常需要将数据存储到磁盘上,而不是内存中。B+树将数据存储在叶子节点中,减少了树的高度,可以更有效地利用磁盘预读,降低磁盘I/O次数。

2.3 常见索引类型(经常记混呜呜呜)

最左匹配原则:是指在联合索引ABC中,查询条件的字段(条件字段顺序不重要)符合索引ABC从左往右连续出现的时候就可以走索引,提升查询效率。但是如果只是出现了一部分或者不连续是无法命中索引的。举例:联合索引(a,b,c)相当于建立了索引(a),(a,b),(a,b,c),而其他组和字段作为查询条件并不能命中该索引。But注意:联合索引遇上范围查询时就会终止。

2.4 索引失效

  1. 查询条件不满足最左匹配原则的,并没有走索引
  2. 查询条件where后使用函数或者计算操作
  3. 使用like模糊查询,like具体内容或者%放在前面的时候不会失效,而是类似于"关键字%"这种%放在后面的会失效
  4. 使用or查询,但凡or的左右两边条件有一个不是索引,那么就整个查询都不走索引
  5. 使用in关键字,查询范围较小会走索引,但查询数据范围比较大的时候就会索引失效
  6. 没覆盖索引时,使用!=、is not null、not like等也不会走索引

2.5 索引优化

在实际工作中经常会遇到系统中出现一些慢SQL的情况,这个时候开发人员就需要进行优化,以提升系统性能。首先使用 Explain 进行分析 SELECT 查询语句,开发人员可以通过分析 Explain 结果来优化查询语句。

比较重要的字段有:

  • select_type : 查询类型,有简单查询、联合查询、子查询等
  • key : 使用的索引
  • rows : 扫描的行数

优化的思路有几个方面:

  1. 减少请求的数据量,就是不要千篇一律的slect *,只返回需要的部分字段即可
  2. 减少扫描行数,这个也就是说去优化索引,该加索引加索引,索引失效的就去解决,走索引了查询性能就上来了
  3. 重构查询方式:一个大查询会导致锁表范围大,可以进行拆分,减少锁表时间
  4. 分解大连接查询:查询关联表太多也会影响性能,如果可以的话尽量改成单表查询
  5. 减少数据量:有的表随着业务发展数据量积累庞大,查询速度变慢是避无可避的,这个时候可考虑分库分表

2.6 分库分表

分库不用说,一个数据库放一些相关的表就行,不要把所有表都放在一个库,一方面数据量庞大影响性能,另一方面,数据库崩一个所有业务全完蛋。而分库没啥好讲的,面试也没遇到过考分库的,主要是分表。

分表方式

  1. 水平切分:称为 Sharding,它是将同一个表中的记录拆分到多个结构相同的表中。当一个表的数据不断增多时,Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。
  2. 垂直切分:将一张表按列切分成多个表,通常是按照列的关系密集程度进行切分,也可以利用垂直切分将经常被使用的列和不经常被使用的列切分到不同的表中。

Sharding策略

  • 哈希取模: hash(key) % NUM_DB
  • 范围: 可以是 ID 范围也可以是时间范围
  • 映射表: 使用单独的一个数据库来存储映射关系

Sharding 存在的问题及解决方案

  1. 事务问题:使用分布式事务来解决
  2. 链接:可以将原来的 JOIN 分解成多个单表查询,然后在用户程序中进行 JOIN。
  3. ID唯一性:
    1. 使用全局唯一 ID: GUID
    2. 为每个分片指定一个 ID 范围
    3. 分布式 ID 生成器 (如 Twitter 的 Snowflake 算法)

3、主从复制与读写分离

3.1 主从复制

主要涉及三个线程: binlog 线程、I/O 线程和 SQL 线程。

  • binlog 线程 : 负责将主服务器上的数据更改写入二进制日志中。
  • I/O 线程 : 负责从主服务器上读取二进制日志,并写入从服务器的中继日志中。
  • SQL 线程 : 负责读取中继日志并重放其中的 SQL 语句。

三种主从复制策略

  1. 异步复制(Async Replication) :默认同步方式是异步复制。主库将更新写入Binlog日志文件后,不需要等待数据更新是否已经复制到从库中,就可以继续处理更多的请求。Master将事件写入binlog,但并不知道Slave是否或何时已经接收且已处理。异步复制提供了最佳性能。
  1. 同步复制(Sync Replication) :主库将更新写入Binlog日志文件后,需要等待数据更新已经复制到从库中,并且已经在从库执行成功,然后才能返回继续处理其它的请求。同步复制提供了最佳安全性,保证数据安全,数据不会丢失,但对性能有一定的影响。
  2. 半同步复制(Semi-Sync Replication):主库提交更新写入二进制日志文件后,等待数据更新写入了从服务器中继日志中,然后才能再继续处理其它请求。该功能确保至少有1个从库接收完主库传递过来的binlog内容已经写入到自己的relay log里面了,才会通知主库上面的等待线程,该操作完毕。半同步复制,是最佳安全性与最佳性能之间的一个折中。

Ps:后两种可以防止主机宕机后数据丢失问题。

主从复制延迟的原因

  • 主服务器的负载过大,被多个睡眠或僵尸线程占用,导致系统负载过大,从库硬件比主库差,导致复制延迟
  • 主从复制单线程,如果主库写作并发太大,来不及传送到从库,就会到导致延迟
  • 慢sql语句过多
  • 网络延迟

解决延迟方法

  • 优化网络连接:确保主从服务器之间的网络连接稳定和高速
  • 优化主从服务器配置:确保主从服务器的硬件配置足够强大,包括CPU、内存和磁盘性能
  • 调整主从同步参数:通过调整MySQL的主从同步参数来优化同步效率。例如,可以调整binlog相关参数,增加binlog大小,调整同步线程数等。
  • 避免长事务:尽量避免长事务的执行
  • 监控和优化数据库性能:定期监控数据库性能,包括主从服务器的负载、IO等情况,及时发现并解决潜在问题
  • 使用并行复制:MySQL 5.6及以上版本支持并行复制,可以提高数据同步的效率,减少延迟
  • 定期清理binlog日志:定期清理不再需要的binlog日志,避免日志文件过大影响同步效率

3.2 读写分离

主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。读写分离能提高性能的原因在于:

  1. 主从服务器负责各自的读和写,极大程度缓解了锁的争用;
  2. 从服务器可以使用 MyISAM,提升查询性能以及节约系统开销;
  3. 增加冗余,提高可用性。

读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器

4、事务和锁

4.1 ACID特性

  • 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败
  • 一致性(Consistency):事务完成时,必须是所有的数据保持一致性状态
  • 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行
  • 持久性(Durability):事务一旦提交或回滚,他对数据库中的数据的该表就是永久的

4.2 隔离级别和存在问题

关于隔离性的扩展,在并发环境下,有四个隔离级别,以及其存在相应的问题:

隔离级别:

  • 读未提交(Read Uncommitted):最低的隔离级别,事务可以读取到其他事务尚未提交的数据,存在脏读(Dirty Read)问题,即读取到未提交的数据,可能导致数据的不一致性。
  • 读已提交(Read Committed):事务只能读取到其他事务已经提交的数据,解决了脏读的问题,但是可能导致不可重复读(Non-Repeatable Read)问题,即在同一事物中多次读取同一数据时可能会得到不同的结果。
  • 可重复读(Repeatable Read):可重复读是MySQL默认的隔离级别,并且解决了不可重复读问题,在一个事务中,多次读取同一数据会得到相同的结果,及时其他事务更改了数据。
  • 串行化读(Serializable):最高的隔离级别,强制所有事务按照顺序依次执行,避免了脏读,不可重读和幻读(Phantom Read),幻读指在同一事务中,多次查询同一个范围的数据时,结果集合的行数可能不一致。

并发读存在的问题:

  1. 脏读:对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的
  2. 幻读:对于两个事务 T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入、删除了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出、少了几行
  3. 不可重复读:对于两个事务 T1, T2, T1 读取了一个字段, 然后 T2 更新并提交了该字段. 之后, T1再次读取同一个字段, 值就不同了

5、MVCC实现机制

5.1 什么是MVCC

MVCC,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。

5.2 MVCC带来的好处

多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制 ,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。 所以MVCC可以为数据库解决以下问题在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题。

5.3 什么是当前读和快照读

了解MVCC之前需要了解一下基础概念,什么是当前读和快照读:

  • 当前读:像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读。它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。
  • 快照读:像不加锁的select操作就是快照读,即不加锁的非阻塞读;

快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。

MVCC就是为了实现读-写冲突不加锁,而这个读指的就是快照读, 而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现

5.4 MVCC 核心

MVCC 的核心依赖于三个部分:

  1. 表的隐藏列:DB_TRX_ID(记录操作当前数据的事务ID)、DB_ROLL_PTR(回滚指针,记录上个版本数据的地址,指向 undo log)、DB_ROW_ID(行 ID,是 MySQL 实例中全局(单个表内,可能不连续)分配的单调递增的值)
  2. undo log:记录数据各版本的修改历史,即"版本链"
  3. Read View:读视图,用于判断哪些数据版本对当前 SELECT 可见

5.5 Redo log 和 undo log

在MySQL中,Redo Log和Undo Log是用来支持事务和保证数据一致性的关键日志机制。

Redo Log(重做日志): 作用是记录了所有对数据库的修改操作,包括插入、更新和删除等操作。记录了事务提交时数据页的物理修改,是用来实现事务的持久性。

  • 工作原理:当事务进行数据修改时,MySQL将修改的操作记录到 Redo Log中,而不直接写入磁盘的数据文件中。这样可以减少磁盘IO的操作,提高性能。在事务提交时,Redo Log的内容会被异步刷新到磁盘上的数据文件中,确保数据的持久性。如果系统崩溃,MySQL可以通过Redo Log中的信息重做之前未写入磁盘的修改操作,恢复到事务提交的状态。
    Undo Log(回滚日志):用来支持事务的回滚操作,即将事务的修改操作撤销,恢复到之前的状态。在insert、update、delete的时候产生的便于数据回滚的日志。

  • 工作原理:当事务进行数据修改时,MySQL将修改的操作记录到Undo Log中,并在事务提交之前保留这些修改的记录。如果事务发生回滚操作,MySQL会根据Undo Log中的信息,将事务的修改操作撤销,将数据还原到事务开始的状态。因此,Undo Log为事务提供了撤销操作的能力,确保数据库的一致性。
    Undo log版本链:在 InnoDB 引擎中,当对数据执行 DML 操作之前,会将改前数据复制一份至 undo log 中。并更新数据行的 DB_ROLL_PTR 字段为 undo log 中该数据副本的地址。同一数据的多个不同版本的副本,则构成了"版本链"。

版本链数据访问规则:

  1. 版本链中的 DB_TRX_ID,不在 未提交的事务 ID 数组 中,且 DB_TRX_ID < max_trx_id,则数据版本对当前事务可见。
  2. 版本链中的 DB_TRX_ID == creator_trx_id,说明数据由当前事务(creator_trx_id),则数据版本对当前事务可见。

5.6 ReadView机制

ReadView(读视图)是 SQL 执行快照读时,MVCC 提取数据的依据,记录并维护系统当前活跃(未提交)事务的 ID。ReadView 中包含 4 个核心字段:

根据不同的隔离级别,生成 ReadView 的时机不同:

  • Read Committed:事物中每次 SELECT 数据时,都会重生成新的 ReadView。确保读取的数据为已经提交的数据。
  • Repeatable Read:只在第一次 SELECT 数据时,生成一个 ReadView,后续 SELECT 数据都复用该 ReadView,确保前后读取的数据一致。但是,若两次 SELECT 之间插入当前读(如DELETE、UPDATE等),则当前读之后的 SELECT 会重新创建 ReadView。

5.7 隔离级别RR判断可见性

RR(可重复读)隔离级别下,创建一个新事务后,执行第一个select语句的时候,innodb会创建一个Read View,Read View 中会保存系统当前其他活跃事务id列表(即trx_ids)。当用户在这个事务中要读取某个记录行的时候,innodb会将该记录行的DB_TRX_ID(记为trx_id)与该Read View中的一些变量进行比较,判断是否满足可见性条件。

  1. 如果数据事务ID trx_id < min_limit_id,表明生成该版本的事务在生成Read View前,已经提交(因为事务ID是递增的),所以该版本可以被当前事务访问。
  2. 如果trx_id>= max_limit_id,表明生成该版本的事务在生成ReadView后才生成,所以该版本不可以被当前事务访问。
  3. 如果 min_limit_id =<trx_id< max_limit_id,需腰分3种情况讨论:
    1. 如果m_ids包含trx_id,则代表Read View生成时刻,这个事务还未提交,但是如果数据的trx_id等于creator_trx_id的话,表明数据是自己生成的,因此是可见的;
    2. b.如果m_ids包含trx_id,并且trx_id不等于creator_trx_id,则Read View生成时,事务未提交,并且不是自己生产的,所以当前事务也是看不见的;
    3. c.如果m_ids不包含trx_id,则说明你这个事务在Read View生成之前就已经提交了,修改的结果,当前事务是能看见的。

6、MySQL中的锁

6.1 锁的分类和区别

锁是计算机协调多个进程或者线程并发访问某一资源的机制。那么如何保证数据并发访问的一致性、有效性是数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素,所以数据库中锁的应用极为重要,其复杂度也更高。

以锁的颗粒度为三类

  • **全局锁:**锁定数据库中的所有表。
  • 表级锁: MySQL 中锁定粒度最大的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM 和 InnoDB 引擎都支持表级锁。
  • **行级锁:**MySQL 中锁定粒度最小的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。 InnoDB 引擎都支持表级锁,MyISAM不支持。

从锁的排他性可以分为两类

  • **共享锁:**共享锁是一种共享访问锁,也称为读锁。多个事务可以同时获取相同数据项的共享锁,彼此之间不会排斥。 共享锁只适用于读操作,它允许多个事务同时读取相同数据,提高了并发性能。
  • **排他锁:**排他锁是一种行锁,也称为写锁。当一个事务获取了排他锁后,其他事务无法再获取该数据的任何锁,包括共享锁和排他锁。 排他锁适用于需要修改数据的操作,它确保在事务修改数据时,其他事务无法读取或修改相同的数据,从而保证了数据的一致性。

从锁的思想可以分为两类

  • **乐观锁:**认为数据在大部分情况下不会发生冲突,因此在数据操作时不会立即加锁。乐观锁通常通过数据版本控制(Version Control)来实现,即在数据表中增加一个版本号字段或时间戳字段。 乐观锁实现方式:一般通过版本号和CAS算法实现。
  • **悲观锁:**认为数据在操作过程中很可能发生冲突,因此在数据操作前就加锁,确保数据在当前事务中的一致性和完整性。悲观锁实现方式:在读取数据时就加锁,其他事务必须等待锁释放后才能进行操作。在MySQL中,悲观锁可以通过 SELECT ... FOR UPDATE 语句实现,将数据行锁定,直到当前事务结束。

乐观锁和悲观锁的区别

  • 锁的时机:乐观锁在数据更新时检查冲突,悲观锁在数据读取时就加锁。
  • 锁的粒度:乐观锁通常不需要数据库锁机制,通过逻辑上的版本控制实现;悲观锁则依赖数据库的锁机制,可能涉及到行锁、表锁等。
  • 性能影响:乐观锁在没有冲突的情况下可以提高性能,减少了锁的开销;悲观锁可能会因为锁的争用导致性能下降。
  • 适用场景:乐观锁适用于冲突较少的环境,悲观锁适用于冲突较多或对数据一致性要求高的环境。
  • 实现复杂度:乐观锁的实现相对简单,主要依赖版本号或时间戳;悲观锁的实现依赖数据库的锁机制,可能更复杂

6.2 InnoDB行锁怎么实现的

InnoDB 的行锁是通过给索引上的索引项加锁来实现的。这意味着,只有在通过索引条件检索数据时,InnoDB 才使用行级锁;如果操作的数据没有使用到索引,那么锁就会退化为表锁。

  • 对于主键索引:直接锁住锁住主键索引即可。
  • 对于普通索引:先锁住普通索引,接着锁住主键索引,这是因为一张表的索引可能存在多个,通过主键索引才能确保锁是唯一的,不然如果同时有2个事务对同1条数据的不同索引分别加锁,那就可能存在2个事务同时操作一条数据了。

6.3 InnoDB 锁的算法有哪几种(都有哪些行锁?)

  • 记录锁(Record Locks):锁定单个索引记录。
  • 间隙锁(Gap Locks):锁定一个区间,但不包括区间的记录。间隙锁主要用于防止幻读,确保在范围查询中,即使在区间内没有记录,也不会插入新的记录。
  • 临键锁(Next-Key Locks):结合了记录锁和间隙锁,锁定一个索引记录及该记录前面的区间。
相关推荐
工作中的程序员5 分钟前
ES 索引或索引模板
大数据·数据库·elasticsearch
UestcXiye8 分钟前
面试算法题精讲:求数组两组数差值和的最大值
面试·数据结构与算法·前后缀分解
严格格8 分钟前
三范式,面试重点
数据库·面试·职场和发展
严文文-Chris24 分钟前
【设计模式-享元】
android·java·设计模式
微刻时光25 分钟前
Redis集群知识及实战
数据库·redis·笔记·学习·程序人生·缓存
单字叶34 分钟前
MySQL数据库
数据库·mysql
mqiqe38 分钟前
PostgreSQL 基础操作
数据库·postgresql·oracle
just-julie40 分钟前
MySQL面试题——第一篇
数据库·mysql
Flying_Fish_roe41 分钟前
浏览器的内存回收机制&监控内存泄漏
java·前端·ecmascript·es6