MySQL— 基础语法大全及操作演示!!!
MySQL进阶 —— 超详细操作演示!!!
锁是计算机协调多个进程或线程 并发访问 某一资源的机制。
在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。
如何保证数据 并发访问 的一致性、有效性是所有数据库必须解决的一个问题,锁冲突 也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。
MySQL中的锁,按照锁的粒度分,分为以下三类:
所有表。整张表。行数据。⭐️ 1). 介绍
全局锁 就是对 整个数据库实例 加锁,加锁后整个实例就处于 只读状态 ,后续的 DML的写语句 ,DDL语句,以及 更新操作 的事务提交语句都将 被阻塞。
其典型的使用场景是做全库的 逻辑备份,对所有的表进行锁定,从而获取 一致性视图,保证 数据的完整性。
为什么全库逻辑备份,就需要加全局锁呢?
A. 我们一起先来分析一下不加全局锁,可能存在的问题。
tb_stock 库存表,tb_order 订单表,tb_orderlog 订单日志表。
tb_stock 库存表。tb_stock表,插入 tb_order表)。tb_order 表的逻辑。tb_orderlog 表。此时备份出来的数据,是存在问题的。因为备份出来的数据,tb_stock 表与 tb_order 表的数据不一致(有最新操作的订单信息,但是库存数没减)。
那如何来规避这种问题呢?
B. 再来分析一下加了全局锁后的情况

对数据库进行进行 逻辑备份 之前,先对整个数据库加上 全局锁 ,一旦加了全局锁之后,其他的 DDL、
DML 全部都处于 阻塞状态,但是可以执行 DQL语句,也就是处于 只读状态,而数据备份 就是 查询操作。
那么数据在进行逻辑备份的过程中,数据库中的数据就是不会发生变化的,这样就保证了数据的 一致性 和 完整性。
⭐️ 2). 语法
a). 加全局锁
flush tables with read lock ;
b). 数据备份
## 不是SQL语句,要在win的命令行中执行!
mysqldump -h 192.168.200.2 -uroot –p1234 rmzh > D:/rmzh.sql
c). 释放锁
unlock tables ;
⭐️ 3). 特点
数据库中加全局锁,是一个比较重的操作,存在以下问题:
binlog ),会导致主从延迟。在 InnoDB引擎 中,我们可以在备份时加上参数 --single-transaction 参数来完成不加锁的 一致性 数据备份。
## 不是SQL语句,要在win的命令行中执行!
mysqldump --single-transaction -uroot –p1234 rmzh > rmzh.sql
⭐️ 1). 介绍
表级锁,每次操作 锁住整张表。
MyISAM、InnoDB、BDB 等存储引擎中。对于表级锁,主要分为以下三类:
meta data lock,MDL)⭐️ 2). 表锁
对于表锁,分为两类:
read lock)write lock)语法:
lock tables 表名... read/write。unlock tables / (客户端断开连接) 。特点:
A. 读锁

测试:

B. 写锁

测试:

结论:
- 读锁 不会阻塞其他客户端的读,但是会阻塞写。
- 写锁 既会阻塞其他客户端的读,又会阻塞其他客户端的写。
⭐️ 3). 元数据锁
meta data lock , 元数据锁,简写 MDL。
这里的 元数据,大家可以简单理解为就是 一张表的表结构。 也就是说,某一张表涉及到 未提交的事务 时,是不能够修改这张表的表结构的。
在MySQL5.5中引入了MDL,当对一张表进行增删改查的时候,加 MDL读锁(共享);当对表结构进行变更操作的时候,加 MDL写锁 (排他)。
常见的SQL操作时,所添加的元数据锁:

演示:
SELECT、INSERT、UPDATE、DELETE 等语句时,添加的是元数据共享锁(SHARED_READ / SHARED_WRITE),之间是 兼容 的。
SELECT 语句时,添加的是 元数据共享锁(SHARED_READ),会阻塞元数据排他锁(EXCLUSIVE),之间是 互斥 的。
我们可以通过下面的SQL,来查看数据库中的 元数据锁 的情况:
select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema.metadata_locks ;
我们在操作过程中,可以通过上述的SQL语句,来查看元数据锁的加锁情况。

⭐️ 4). 意向锁
a). 介绍
假如没有意向锁,客户端一对表加了行锁后,客户端二如何给表加表锁呢,来通过示意图简单分析一下:


有了意向锁之后 :


b). 分类
IS): 由语句 select ... lock in share mode 添加 。 与 表锁共享锁( read )兼容,与表锁排他锁( write )互斥。IX): 由 insert、update、delete、select...for update 添加 。与表锁共享锁( read )及 排他锁( write )都互斥,意向锁之间不会互斥。一旦事务提交了,意向共享锁、意向排他锁,都会自动释放。
可以通过以下SQL,查看意向锁 及 行锁 的加锁情况:
select object_schema, object_name, index_name, lock_type, lock_mode, lock_data from performance_schema.data_locks;
演示:
A. 意向共享锁 与 表读锁 是 兼容 的

B. 意向排他锁 与 表读锁、写锁 都是 互斥 的

⭐️ 1). 介绍
行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在 InnoDB 存储引擎中(MyISAM 不支持)。
InnoDB的数据是基于索引组织的,行锁是通过对 索引 (聚集索引) 上的索引项加锁来实现的,而不是对记录加的锁。对于行级锁,主要分为以下三类:
Record Lock):锁定单个行记录的锁,防止其他事务对此行进行 update 和 delete。在 RC、RR隔离级别下都支持。
Gap Lock):锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行 insert,产生幻读。在 RR 隔离级别下都支持。
Next-Key Lock):行锁和间隙锁组合,同时锁住数据,并锁住数据前面的 间隙 Gap。在RR隔离级别下支持。
⭐️ 2). 行锁
a). 介绍
InnoDB实现了以下两种类型的行锁:
S):允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁。X):允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。两种行锁的兼容情况如下:

常见的SQL语句,在执行时,所加的行锁如下:

b). 演示
默认情况下,InnoDB 在 REPEATABLE READ 事务隔离级别运行,InnoDB 使用 next-key 锁进行搜索和索引扫描,以防止幻读。
InnoDB 的 行锁 是针对于 索引加的锁,不通过索引条件检索数据,那么 InnoDB 将对表中的所有记录加锁,此时 就会升级为 表锁。可以通过以下SQL,查看意向锁及行锁的加锁情况:
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;
示例演示
数据准备:
CREATE TABLE `stu` (
`id` int NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int NOT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4;
INSERT INTO `stu` VALUES (1, 'tom', 1);
INSERT INTO `stu` VALUES (3, 'cat', 3);
INSERT INTO `stu` VALUES (8, 'rose', 8);
INSERT INTO `stu` VALUES (11, 'jetty', 11);
INSERT INTO `stu` VALUES (19, 'lily', 19);
INSERT INTO `stu` VALUES (25, 'luci', 25);
演示行锁的时候,我们就通过上面这张表来演示一下。
select 语句,执行时,不会加锁。
select...lock in share mode,加共享锁,共享锁与共享锁之间兼容。

客户端一获取的是
id为1这行的共享锁,客户端二是可以获取id为3这行的 排它锁 的,因为不是同一行数据。 而如果客户端二想获取id为1这行的 排他锁,会处于==阻塞状态==,因为为共享锁与排他锁之间互斥。

当客户端一,执行
update语句,会为id为1的记录加 排他锁; 客户端二,如果也执行update语句更新id为1的数据,也要为id为1的数据加排他锁,但是客户端二会处于 阻塞状态,因为排他锁之间是互斥的。 直到客户端一,把事务提交了,才会把这一行的行锁释放,此时客户端二,解除阻塞。


在客户端一中,开启事务,并执行
update语句,更新name为Lily的数据,也就是id为19的记录 。然后在客户端二中更新id为3的记录,却不能直接执行,会处于阻塞状态,为什么呢?
- 原因就是因为此时,客户端一,根据
name字段进行更新时,name字段是没有索引的,如果没有索引,此时行锁会升级为表锁(因为行锁是对索引项加的锁,而name没有索引)。

此时我们可以看到,客户端一,开启事务,然后依然是根据
name进行更新。而客户端二,在更新id为3的数据时,更新成功,并 未进入 阻塞状态。 这样就说明,我们根据索引字段进行更新操作,就可以 避免 行锁 升级为 表锁 的情况。
⭐️ 3). 间歇锁 & 临键锁
默认情况下,InnoDB 在 REPEATABLE READ 事务隔离级别运行,InnoDB 使用 next-key 锁进行搜索和索引扫描,以防止幻读。
next-key lock 退化为 间隙锁。注意:间隙锁 唯一目的是防止其他事务插入间隙。间隙锁 可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁。
示例演示

非唯一普通索引),向右遍历时最后一个值不满足查询需求时,next-key lock 退化为间隙锁。介绍分析一下:
我们知道InnoDB的B+树索引,叶子节点是有序的双向链表。 假如,我们要根据这个二级索引查询值
为18的数据,并加上共享锁,我们是只锁定18这一行就可以了吗? 并不是,因为是非唯一索引,这个
结构中可能有多个18的存在,所以,在加锁时会继续往后找,找到一个不满足条件的值(当前案例中也
就是29)。此时会对18加临键锁,并对29之前的间隙加锁。



查询的条件为
id>=19,并添加共享锁。 此时我们可以根据数据库表中现有的数据,将数据分为三个部
分:
[19]
(19,25]
(25,+∞]
所以数据库数据在加锁是,就是将19加了行锁,25的临键锁(包含25及25之前的间隙),正无穷的临键锁(正无穷及之前的间隙)。
🚀🚀🚀 锁 快速食用:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
## 1、概述
-- 在并发访问时,解决数据访问的一致性、有效性问题
-- 全局锁、表级锁、行级锁
## 2、全局锁
-- 对整个数据库实例加锁,加锁后整个实例就处于只读状态
-- 性能较差,数据逻辑备份时使用
## 3、表级锁
-- 操作锁住整张表,锁定粒度大,发生锁冲突的概率高
-- 表锁、元数据锁、意向锁
## 4、行级锁
-- 操作锁住对应的行数据,锁定粒度最小,发生锁冲突的概率最低
-- 行锁、间隙锁、临键锁
InnoDB的 逻辑存储 结构如下图所示:

1). 表空间
InnoDB 存储引擎 逻辑结构的最高层;innodb_file_per_table (在8.0版本中默认开启) ,则每张表都会有一个 表空间(xxx.ibd),一个 mysql 实例可以 对应 多个表空间,用于存储记录、索引等数据。
2). 段
Leaf node segment )、索引段(Non-leaf node segment)、回滚段(Rollback segment);InnoDB 是 索引组织表,数据段就是 B+树 的 叶子节点, 索引段即为B+树的 非叶子节点。Extent(区)。3). 区
1M。InnoDB 存储引擎页大小为 16K, 即一个区中一共有 64 个 连续的页。4). 页
InnoDB 存储引擎 磁盘管理 的 最小单元,每个页的大小默认为 16KB。InnoDB 存储引擎每次从磁盘申请 4-5 个区。5). 行
InnoDB 存储引擎 数据是按行进行存放的。Trx_id:每次对某条记录进行改动时,都会把对应的事务 id 赋值给 trx_id 隐藏列。Roll_pointer:每次对某条引记录进行改动时,都会把旧的版本写入到 undo日志中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。⭐️ 1). 概述
InnoDB 存储引擎,它擅长事务处理,具有崩溃恢复特性,在日常开发中使用非常广泛。下面是 InnoDB 架构图,左侧为内存结构,右侧为磁盘结构。

⭐️ 2). 内存结构
Buffer Pool(缓冲池)、Change Buffer、Adaptive Hash Index、Log Buffer。 接下来介绍一下这四个部分。
a). Buffer Pool
InnoDB 存储引擎基于 磁盘文件 存储,访问 物理硬盘 和在 内存 中进行访问,速度相差很大,为了尽可能弥补这两者之间的I/O效率的差值,就需要把经常使用的数据加载到 缓冲池 中,避免每次访问都进行磁盘I/O。InnoDB 的缓冲池中不仅缓存了 索引页 和 数据页,还包含了 undo页、插入缓存、自适应哈希索引 以及InnoDB的锁信息等等。缓冲池 Buffer Pool,是主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),然后再以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度。
缓冲池以 Page 页为单位,底层采用 链表数据结构管理 Page。根据状态,将Page分为三种类型:
free page:空闲page,未被使用。clean page:被使用page,数据没有被修改过。dirty page:脏页,被使用 page,数据被修改过,也中数据与磁盘的数据产生了不一致。在专用服务器上,通常将多达80%的物理内存分配给缓冲池 。参数设置: show variables like 'innodb_buffer_pool_size';
b). Change Buffer
Change Buffer,更改缓冲区(针对于 *非唯一 二级索引页 ),在执行 DML 语句时,如果这些数据 Page 没有在Buffer Pool中,不会直接操作磁盘,而会将数据变更存在 更改缓冲区 Change Buffer中,在未来数据被读取时,再将数据合并恢复到 Buffer Pool 中,再将合并后的数据刷新到磁盘中。Change Buffer 的意义是什么呢?

与聚集索引不同,二级索引通常是非唯一的,并且以相对随机的顺序插入二级索引。
同样,删除和更新可能会影响索引树中不相邻的二级索引页,如果每一次都操作磁盘,会造成大量的磁盘IO。有了Change Buffer之后,我们可以在缓冲池中进行合并处理,减少磁盘IO。
c). Adaptive Hash Index
Buffer Pool 数据的查询。innoDB 引擎中虽然没有直接支持hash索引,但是给我们提供了一个功能就是这个自适应hash索引。因为前面我们讲到过,hash索引在进行等值匹配时,一般性能是要高于B+树的,因为hash索引一般只需要一次IO即可,而B+树,可能需要几次匹配,所以hash索引的效率要高,但是hash索引又不适合做范围查询、模糊匹配等。自适应哈希索引,无需人工干预,是系统根据情况自动完成。
adaptive_hash_index
d). Log Buffer
log日志数据(redo log 、undo log),默认大小为 16MB,日志缓冲区的日志会定期刷新到磁盘中。参数:
innodb_log_buffer_size:缓冲区大小innodb_flush_log_at_trx_commit:日志刷新到磁盘时机,取值主要包含以下三个:
1: 日志在每次事务提交时写入并刷新到磁盘,默认值。0: 每秒将日志写入并刷新到磁盘一次。2: 日志在每次事务提交后写入,并每秒刷新到磁盘一次。
⭐️ 3). 磁盘结构

a). System Tablespace
系统表空间 是 更改缓冲区的存储区域。
如果表是在 系统表空间 而不是每个表文件或通用表空间中创建的,它也可能包含表和索引数据。(在MySQL5.x版本中还包含 InnoDB数据字典、undolog 等)
参数:innodb_data_file_path
系统表空间,默认的文件名叫 ibdata1。
b). File-Per-Table Tablespaces
如果开启了innodb_file_per_table 开关 ,则每个表的 文件表空间 包含单个 InnoDB 表的数据和索引 ,并存储在文件系统上的单个数据文件中。
开关参数:innodb_file_per_table ,该参数默认开启。
那也就是说,我们每创建一个表,都会产生一个表空间文件,如图:
c). General Tablespaces
CREATE TABLESPACE 语法创建通用表空间,在创建表时,可以指定该表空间。CREATE TABLESPACE ts_name ADD DATAFILE 'file_name' ENGINE = engine_name;
CREATE TABLE xxx ... TABLESPACE ts_name;
d). Undo Tablespaces
undo 表空间(初始大小 16M ),用于存储 undo log日志。e). Temporary Tablespaces
InnoDB 使用 会话临时表空间 和 全局临时表空间。存储用户创建的临时表等数据。f). Doublewrite Buffer Files
innoDB 引擎将数据页从 Buffer Poo l刷新到磁盘前,先将数据页写入双写缓冲区文件中,便于系统异常时恢复数据。g). Redo Log
redo log buffer)以及重做日志文件(redo log),前者是在内存中,后者在磁盘中。前面我们介绍了InnoDB的内存结构,以及磁盘结构,那么内存中我们所更新的数据,又是如何到磁盘中的呢?

⭐️ 4). 后台线程

在InnoDB 的后台线程中,分为4类,分别是:Master Thread 、IO Thread、Purge Thread、Page Cleaner Thread。
a). Master Thread
undo页的回收 。b). IO Thread
InnoDB 存储引擎中大量使用了 AIO(异步非阻塞IO) 来处理IO请求, 这样可以极大地提高数据库的性能,而 IOThread主要负责这些 IO请求的回调。
InnoDB 的状态信息,其中就包含 IO Thread 信息。show engine innodb status \G;

c). Purge Thread
undo log,在事务提交之后,undo log 可能不用了,就用它来回收。d). Page Cleaner Thread
Master Thread 刷新脏页到磁盘的线程,它可以减轻 Master Thread 的工作压力,减少阻塞。⭐️ 1). 事务基础
a). 事务
b). 特性
Atomicity ):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。Consistency ):事务完成时,必须使所有的数据都保持一致状态。Isolation ):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。Durability ):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。那实际上,我们研究事务的原理,就是研究MySQL的InnoDB引擎是如何保证事务的这四大特性的。

而对于这四大特性,实际上分为两个部分。
redo log日志,一份是undo log 日志。MVCC 来保证的。
我们在讲解事务原理的时候,主要就是来研究一下 redolog,undolog 以及 MVCC。
⭐️ 2). redo log
redo log buffer)以及重做日志文件(redo log file),前者是在 内存 中,后者在 磁盘 中。当事务提交之后会把所有修改信息都存到该日志文件中, 用于在刷新脏页到磁盘,发生错误时, 进行数据恢复使用。如果没有 redo log,可能会存在什么问题的? 我们一起来分析一下。
我们知道,在InnoDB引擎中的内存结构中,主要的内存区域 就是 缓冲池,在缓冲池中缓存了很多的数据页。
- 当我们在一个事务中,执行多个增删改的操作时,InnoDB引擎会先操作缓冲池中的数据,如果 缓冲区 没有对应的数据,会通过 后台线程 将磁盘中的数据加载出来,存放在 缓冲区 中,然后将缓冲池中的数据修改,修改后的数据页我们称为 脏页。
- 而 脏页 则会在一定的时机,通过后台线程刷新到磁盘中,从而保证缓冲区与磁盘的数据一致。 而缓冲区的脏页数据并不是实时刷新的,而是一段时间之后将缓冲区的数据刷新到磁盘中,假如刷新到磁盘的过程出错了,而提示给用户事务提交成功,而数据却没有持久化下来,这就出现问题了,没有保证事务的持久性。

那么,如何解决上述的问题呢? 在InnoDB中提供了一份日志 redo log,接下来我们再来分析一下,通过 redolog 如何解决这个问题。

有了
redolog之后,当对缓冲区的数据进行增删改之后,会首先将操作的 数据页的变化,记录在redo log buffer中。在事务提交时,会将redo log buffer中的数据刷新到redo log磁盘文件中。
过一段时间之后,如果 刷新缓冲区 的 脏页 到磁盘时,发生错误,此时就可以借助于redo log进行数据恢复,这样就 保证了事务的持久性。
而如果脏页成功刷新到磁盘 或 涉及到的数据已经落盘,此时redo log就没有作用了,就可以删除了,所以存在的两个redo log文件是循环写的。
那为什么每一次提交事务,要刷新
redo log到磁盘中呢,而不是直接将buffer pool中的脏页刷新到磁盘呢 ?
- 因为在业务操作中,我们操作数据一般都是随机读写磁盘的,而不是顺序读写磁盘。 而
redo log在往磁盘文件中写入数据,由于是日志文件,所以都是顺序写的。顺序写的效率,要远大于随机写。- 这种 先写日志 的方式,称之为
WAL(Write-Ahead Logging)。
⭐️ 3). undo log
undo log 和 redo log 记录 物理日志 不一样,它是 逻辑日志。可以认为当 delete 一条记录时,undo log 中会记录一条对应的 insert 记录,反之亦然,当 update 一条记录时,它记录一条对应相反的 update 记录。当执行 rollback 时,就可以从 undo log 中的逻辑记录读取到相应的内容并进行回滚。Undo log 销毁:undo log 在事务执行时产生,事务提交时,并不会立即删除 undo log,因为这些日志可能还用于 MVCC。Undo log 存储:undo log 采用 段的方式 进行管理和记录,存放在前面介绍的 rollback segment 回滚段 中,内部包含1024个 undo log segment。⭐️ 1). 基本概念
a). 当前读
select ... lock in share mode (共享锁),select ... for update、update、insert、delete(排他锁) 都是一种 当前读。测试:

在测试中我们可以看到,即使是在默认的 RR隔离级别 下,事务A中依然可以读取到事务B最新提交的内容,因为在查询语句后面加上了
lock in share mode共享锁,此时是当前读操作。当然,当我们加排他锁的时候,也是当前读操作。
b). 快照读
select(不加锁)就是快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。Read Committed:每次 select,都生成一个快照读。Repeatable Read:开启事务后第一个 select 语句才是快照读的地方。Serializable:快照读会 退化 为 当前读。测试:

在测试中,我们看到即使 事务B提交了数据,事务A中也查询不到 。
- 原因就是因为普通的
select是 快照读,而在当前默认的 RR隔离级别下,开启事务后第一个select语句才是快照读的地方,后面执行相同的select语句都是 从快照中获取数据,可能不是当前的最新数据,这样也就 保证了可重复读。
c). MVCC
Multi-Version Concurrency Control,多版本并发控制。MVCC 提供了一个 非阻塞读功能。三个隐式字段、undo log日志、readView。接下来,我们再来介绍一下InnoDB引擎的表中涉及到的 隐藏字段 、undolog 以及 readview,从而来介绍一下MVCC的原理。
⭐️ 2). 隐藏字段
a). 介绍


而上述的前两个字段是肯定会添加的, 是否添加最后一个字段 DB_ROW_ID,得看当前表有没有主键,如果有主键,则不会添加该隐藏字段。
b). 测试:
查看有主键的表 stu
/var/lib/mysql/rmzh/ , 查看stu的表结构信息, 通过如下指令:ibd2sdi stu.ibd

columns,在其中我们会看到处理我们建表时指定的字段以外,还有额外的两个字段 分别是:DB_TRX_ID 、 DB_ROLL_PTR ,因为该表有主键,所以没有 DB_ROW_ID 隐藏字段。
c). 查看没有主键的表 employee
create table employee (id int , name varchar(10));
ibd2sdi employee.ibd

columns,在其中我们会看到处理我们建表时指定的字段以外,还有额外的三个字段 分别是:DB_TRX_ID 、 DB_ROLL_PTR 、DB_ROW_ID,因为 employee 表是没有指定主键的。⭐️ 3). undolog
a). 介绍
insert、update、delete 的时候产生的便于数据回滚的日志。insert 的时候,产生的 undo log 日志只在回滚时需要,在事务提交后,可被 立即删除 。update、delete 的时候,产生的 undo log 日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。b). 版本链
有一张表原始数据为:

DB_TRX_ID : 代表最近 修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID,是自增的。
DB_ROLL_PTR : 由于这条数据是才插入的,没有被更新过,所以该字段值为null。
然后,有四个并发事务同时在访问这张表。

当 事务2 执行第一条修改语句时,会记录 undo log 日志,记录数据变更之前的样子; 然后更新记录,且记录本次操作的 事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。

B.第二步

当 事务3 执行第一条修改语句时,也会记录 undo log 日志,记录数据变更之前的样子; 然后更新记录,并且记录本次操作的事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。

C. 第三步

当事务4执行第一条修改语句时,也会记录 undo log 日志,记录数据变更之前的样子; 然后更新记录,并且记录本次操作的事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。

最终我们发现,不同事务 或 相同事务 对同一条记录进行修改,会导致该记录的
undo log生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。
⭐️ 4). readview
ReadView(读视图)是 快照读 SQL执行时MVCC提取数据的依据,记录并维护系统 当前活跃的事务(未提交的)id。
ReadView中包含了四个核心字段:

而在 readview 中就规定了 版本链 数据的访问规则:
trx_id 代表当前 undolog 版本链 对应 事务ID。
不同的隔离级别,生成 ReadView 的时机不同:
READ COMMITTED :在事务中 每一次 执行 快照读 时生成 ReadView。REPEATABLE READ:仅在事务中第一次执行 快照读 时生成 ReadView,后续复用 该 ReadView。⭐️ 5). 原理分析
a). RC隔离级别
ReadView。我们就来分析事务5中,两次快照读读取数据,是如何获取数据的?
id 为30的记录,由于隔离级别为 Read Committed,所以每一次进行 快照读 都会生成一个 ReadView,那么两次生成的 ReadView 如下。
ReadView 以及 ReadView 的版本链访问规则,到 undo log版本链中匹配数据,最终决定此次快照读返回的数据。A. 先来看第一次快照读具体的读取过程:

undo log 的版本链,从上到下进行挨个匹配:

B. 再来看第二次快照读具体的读取过程:

在进行匹配时,会从undo log的版本链,从上到下进行挨个匹配:

b). RR隔离级别
ReadView,后续复用该ReadView。 而 RR 是可重复读,在一个事务中,执行两次相同的 select 语句,查询到的结果是一样的。那MySQL是如何做到可重复读的呢? 我们简单分析一下就知道了

ReadView,后续都是复用该ReadView,那么既然 ReadView 都一样, ReadView 的版本链匹配规则也一样, 那么最终快照读返回的结果也是一样的。所以呢,MVCC的实现原理就是通过 InnoDB 表的隐藏字段、UndoLog 版本链、ReadView来实现的。
而MVCC + 锁,则实现了事务的隔离性。 而一致性则是由 redolog 与 undolog 保证。

🚀🚀🚀 InnoDB 引擎 快速食用:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
## 1. 逻辑存储结构
表空间、段、区(1M)、页(16K)、行
## 2、架构
内存结构
磁盘结构
## 3、事务原理
原子性 - undo log
持久性 - redo log
一致性 - undo log + redo log
隔离性 - 锁 + MVCC
## 4、MVCC (多版本并发控制)
记录隐藏字段、undo log版本链、readView (读视图)
Mysql数据库安装完成后,自带了以下四个数据库,具体作用如下:


⭐️ 1). mysql
mysql 不是指 mysql 服务,而是指 mysql 的客户端工具。语法 :
mysql [options] [database]
选项 :
-u, --user=name #指定用户名
-p, --password[=name] #指定密码
-h, --host=name #指定服务器IP或域名
-P, --port=port #指定连接端口
-e, --execute=name #执行SQL语句并退出
-e 选项可以在Mysql客户端执行SQL语句,而不用连接到MySQL数据库再执行,对于一些批处理脚本,这种方式尤其方便。示例:
## 不用登录MySQL
mysql -h192.168.200.202 -P3306 -uroot -p1234 rmzh -e "select * from stu";
mysql -uroot -p1234 rmzh -e "select * from stu";

⭐️ 2). mysqladmin
mysqladmin 是一个执行管理操作的客户端程序。可以用它来检查服务器的 配置 和 当前状态、创建并删除 数据库等。通过帮助文档查看选项:
mysqladmin --help


语法:
mysqladmin [options] command ...
选项:
-u, --user=name #指定用户名
-p, --password[=name] #指定密码
-h, --host=name #指定服务器IP或域名
-P, --port=port #指定连接端口
示例:
## 如果不指定主机名及主机端口号,代表查看本机3306 MySQL
mysqladmin -uroot -p1234 drop 'test01';
mysqladmin -uroot -p1234 version;
mysqladmin -uroot -p1234 create db02;


⭐️ 3). mysqlbinlog
mysqlbinlog 日志管理工具。语法 :
mysqlbinlog [options] log-files1 log-files2 ...
选项 :
-d, --database=name 指定数据库名称,只列出指定的数据库相关操作。
-o, --offset=# 忽略掉日志中的前n行命令。
-r,--result-file=name 将输出的文本格式日志输出到指定文件。
-s, --short-form 显示简单格式, 省略掉一些信息。
--start-datatime=date1 --stop-datetime=date2 指定日期间隔内的所有日志。
--start-position=pos1 --stop-position=pos2 指定位置间隔内的所有日志。
示例:
binlog.000008 这个二进制文件中的数据信息

⭐️ 4). mysqlshow
mysqlshow 客户端对象查找工具,用来很快地 查找 存在哪些 数据库、数据库中的表、表中的列 或者 索引。语法 :
mysqlshow [options] [db_name [table_name [col_name]]]
选项 :
--count 显示数据库及表的统计信息(数据库,表 均可以不指定)
-i 显示指定数据库或者指定表的状态信息
示例:
#查询test库中每个表中的字段书,及行数
mysqlshow -uroot -p2143 test --count
#查询test库中book表的详细情况
mysqlshow -uroot -p2143 test book --count
示例:
mysqlshow -uroot -p1234 --count

rmzh 的统计信息mysqlshow -uroot -p1234 rmzh --count

rmzh 中的 course 表的信息mysqlshow -uroot -p1234 rmzh course --count

rmzh 中的 course 表的 id 字段的信息mysqlshow -uroot -p1234 rmzh course id --count

⭐️ 5). mysqldump
mysqldump 客户端工具用来 备份数据库 或在 不同数据库之间进行数据迁移。备份内容包含创建表,及插入表的SQL语句。语法 :
mysqldump [options] db_name [tables]
mysqldump [options] --database/-B db1 [db2 db3...]
mysqldump [options] --all-databases/-A
连接选项 :
-u, --user=name 指定用户名
-p, --password[=name] 指定密码
-h, --host=name 指定服务器ip或域名
-P, --port=# 指定连接端口
输出选项:
--add-drop-database 在每个数据库创建语句前加上 drop database 语句
--add-drop-table 在每个表创建语句前加上 drop table 语句 , 默认开启 ; 不
开启 (--skip-add-drop-table)
-n, --no-create-db 不包含数据库的创建语句
-t, --no-create-info 不包含数据表的创建语句
-d --no-data 不包含数据
-T, --tab=name 自动生成两个文件:一个.sql文件,创建表结构的语句;一个.txt文件,数据文件
示例:
rmzh 数据库mysqldump -uroot -p1234 rmzh > rmzh.sql

rmzh.sql,来查看备份出来的数据到底什么样。cat rmzh.sql
备份出来的数据包含:
- 删除表的语句
- 创建表的语句
- 数据插入语句
如果我们在数据备份时,不需要创建表,或者不需要备份数据,只需要备份表结构,都可以通过对应的参数来实现。
rmzh 数据库中的表数据,不备份表结构( -t )mysqldump -uroot -p1234 -t rmzh > rmzh01.sql
打开 rmzh01.sql ,来查看备份的数据,只有 insert 语句,没有备份表结构。
rmzh 数据库的表的 表结构 与 数据 分开备份( -T )mysqldump -uroot -p1234 -T /root rmzh score

执行上述指令,会出错,数据不能完成备份,原因是因为我们所指定的数据存放目录
/root,MySQL认为是不安全的,需要存储在MySQL信任的目录下。那么,哪个目录才是MySQL信任的目录呢,可以查看一下系统变量secure_file_priv。执行结果如下:


上述的两个文件 score.sql 中记录的就是表结构文件,而 score.txt 就是表数据文件,但是需要注意表数据文件,并不是记录一条条的 insert 语句,而是按照一定的格式记录表结构中的数据。如下:

⭐️ 6). mysqlimport/source
mysqlimport 是客户端数据导入工具,用来导入 mysqldump 加 -T 参数后导出的 文本文件。语法 :
mysqlimport [options] db_name textfile1 [textfile2...]
示例 :
mysqlimport -uroot -p2143 test /tmp/city.txt

sql 文件,可以使用 mysql 中的 source 指令 :语法 :
source /root/xxxxx.sql # 在mysql 的命令行中执行
🚀🚀🚀 MySQL 管理 快速食用:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
## 1、mysql
Mysql 客户端工具,-e 执行SQL并退出 # 通常在一些脚本编写的时候会用到这个工具
## 2、mysqladmin
Mysql 管理工具
## 3、mysqlbinlog
二进制日志查看工具
## 4、mysqlshow
查看数据库、表、字段的统计信息
## 5、mysqldump
数据备份工具
## 6、mysqlimport/source
数据导入
注:仅供学习参考,如有不足,欢迎指正!!!