MySQL存储引擎

什么是存储引擎

img

MySQL引擎:

可以理解为,MySQL的“文件系统”,只不过功能更加强大。

存储引擎的类型

MySQL 提供以下存储引擎:

  • 01)InnoDB
  • 02)MyISAM
  • 03)MEMORY
  • 04)ARCHIVE
  • 05)FEDERATED
  • 06)EXAMPLE
  • 07)BLACKHOLE
  • 08)MERGE
  • 09)NDBCLUSTER
  • 10)CSV

查看表的存储引擎

root@localhost [(none)] >show create table world.city;
root@localhost:world>select table_schema,table_name,engine from information_schema.tables where engine='innodb';
+---------------+----------------------+--------+
| table_schema  | table_name           | engine |
+---------------+----------------------+--------+
| hg            | stu                  | InnoDB |
| hg            | student              | InnoDB |
| hg1           | stu                  | InnoDB |
| mtlbbdb_19900 | t_achievement        | InnoDB |
| mtlbbdb_19900 | t_auctionprice       | InnoDB |
| mtlbbdb_19900 | t_backup_tmp_guid    | InnoDB |
| mtlbbdb_19900 | t_belle              | InnoDB |
| mtlbbdb_19900 | t_char               | InnoDB |
| mtlbbdb_19900 | t_char_ext1          | InnoDB |
| mtlbbdb_19900 | t_char_ext2          | InnoDB |
| mtlbbdb_19900 | t_char_ext3          | InnoDB |
| mtlbbdb_19900 | t_char_ext4          | InnoDB |
| mtlbbdb_19900 | t_chat               | InnoDB |
| mtlbbdb_19900 | t_chrank             | InnoDB |
| mtlbbdb_19900 | t_consignsale        | InnoDB |
| mtlbbdb_19900 | t_desk               | InnoDB |
| mtlbbdb_19900 | t_fellow             | InnoDB |
| mtlbbdb_19900 | t_general_set        | InnoDB |
| mtlbbdb_19900 | t_goldmine           | InnoDB |
| mtlbbdb_19900 | t_guid               | InnoDB |
| mtlbbdb_19900 | t_guild              | InnoDB |
| mtlbbdb_19900 | t_guild_log          | InnoDB |
| mtlbbdb_19900 | t_guild_user         | InnoDB |
| mtlbbdb_19900 | t_herocode           | InnoDB |
| mtlbbdb_19900 | t_hongbao            | InnoDB |
| mtlbbdb_19900 | t_impact             | InnoDB |
| mtlbbdb_19900 | t_item               | InnoDB |
| mtlbbdb_19900 | t_jieyi              | InnoDB |
| mtlbbdb_19900 | t_jieyi_user         | InnoDB |
| mtlbbdb_19900 | t_liuyan             | InnoDB |
| mtlbbdb_19900 | t_luckdraw           | InnoDB |
| mtlbbdb_19900 | t_mail               | InnoDB |
| mtlbbdb_19900 | t_master             | InnoDB |
| mtlbbdb_19900 | t_master_user        | InnoDB |
| mtlbbdb_19900 | t_mission            | InnoDB |
| mtlbbdb_19900 | t_offlinecommand     | InnoDB |
| mtlbbdb_19900 | t_push               | InnoDB |
| mtlbbdb_19900 | t_randomname         | InnoDB |
| mtlbbdb_19900 | t_rank               | InnoDB |
| mtlbbdb_19900 | t_redeem             | InnoDB |
| mtlbbdb_19900 | t_relation           | InnoDB |
| mtlbbdb_19900 | t_shenyi             | InnoDB |
| mtlbbdb_19900 | t_shoppinglist       | InnoDB |
| mtlbbdb_19900 | t_spaceaction        | InnoDB |
| mtlbbdb_19900 | t_spacecomment       | InnoDB |
| mtlbbdb_19900 | t_tutor              | InnoDB |
| mtlbbdb_19900 | t_tutor_user         | InnoDB |
| mtlbbdb_19900 | t_usermail           | InnoDB |
| mtlbbdb_19900 | t_wordsman           | InnoDB |
| mtlbbdb_19900 | t_world_globaldata   | InnoDB |
| mtlbbdb_19900 | t_wulin_zhidian      | InnoDB |
| mysql         | innodb_index_stats   | InnoDB |
| mysql         | innodb_table_stats   | InnoDB |
| mysql         | slave_master_info    | InnoDB |
| mysql         | slave_relay_log_info | InnoDB |
| mysql         | slave_worker_info    | InnoDB |
| world         | city                 | InnoDB |
| world         | country              | InnoDB |
| world         | countrylanguage      | InnoDB |
+---------------+----------------------+--------+
root@localhost [(none)] >select table_schema,table_name,engine from information_schema.tables where engine='myisam'; 
+--------------------+---------------------------+--------+
| table_schema       | table_name                | engine |
+--------------------+---------------------------+--------+
| information_schema | COLUMNS                   | MyISAM |
| information_schema | EVENTS                    | MyISAM |
| information_schema | OPTIMIZER_TRACE           | MyISAM |
| information_schema | PARAMETERS                | MyISAM |
| information_schema | PARTITIONS                | MyISAM |
| information_schema | PLUGINS                   | MyISAM |
| information_schema | PROCESSLIST               | MyISAM |
| information_schema | ROUTINES                  | MyISAM |
| information_schema | TRIGGERS                  | MyISAM |
| information_schema | VIEWS                     | MyISAM |
| mysql              | columns_priv              | MyISAM |
| mysql              | db                        | MyISAM |
| mysql              | event                     | MyISAM |
| mysql              | func                      | MyISAM |
| mysql              | help_category             | MyISAM |
| mysql              | help_keyword              | MyISAM |
| mysql              | help_relation             | MyISAM |
| mysql              | help_topic                | MyISAM |
| mysql              | ndb_binlog_index          | MyISAM |
| mysql              | plugin                    | MyISAM |
| mysql              | proc                      | MyISAM |
| mysql              | procs_priv                | MyISAM |
| mysql              | proxies_priv              | MyISAM |
| mysql              | servers                   | MyISAM |
| mysql              | tables_priv               | MyISAM |
| mysql              | time_zone                 | MyISAM |
| mysql              | time_zone_leap_second     | MyISAM |
| mysql              | time_zone_name            | MyISAM |
| mysql              | time_zone_transition      | MyISAM |
| mysql              | time_zone_transition_type | MyISAM |
| mysql              | user                      | MyISAM |
+--------------------+---------------------------+--------+

InnoDB与MyiSAM的区别

物理区别

# MyiSAM
[root@db01 ~]# ll /app/mysql/data/mysql/user.*
-rw-rw---- 1 mysql mysql 10684 Jul 18 14:55 /app/mysql/data/mysql/user.frm
-rw-rw---- 1 mysql mysql   344 Jul 25 17:49 /app/mysql/data/mysql/user.MYD
-rw-rw---- 1 mysql mysql  2048 Jul 25 17:49 /app/mysql/data/mysql/user.MYI

# InnoDB
[root@db01 ~]# ll /app/mysql/data/world/city.*
//表结构
-rw-rw---- 1 mysql mysql   8710 Jul 24 10:46 /app/mysql/data/world/city.frm
//表空间(真实数据都在这,又名独立表空间:只属于city这张表)
-rw-rw---- 1 mysql mysql 589824 Jul 24 10:46 /app/mysql/data/world/city.ibd

format:格式,结构
.rrm都是表结构信息
root@localhost:(none)>desc world.city;
+-------------+----------+------+-----+---------+----------------+
| Field       | Type     | Null | Key | Default | Extra          |
+-------------+----------+------+-----+---------+----------------+
| ID          | int(11)  | NO   | PRI | NULL    | auto_increment |
| Name        | char(35) | NO   |     |         |                |
| CountryCode | char(3)  | NO   | MUL |         |                |
| District    | char(20) | NO   |     |         |                |
| Population  | int(11)  | NO   |     | 0       |                |
+-------------+----------+------+-----+---------+----------------+

逻辑上的区别

img

innodb核心特性

重点:

  • MVCC 多版本并发控制
  • 事务
  • 行级锁
  • 热备份
  • Crash Safe Recovery(自动故障恢复)

存储引擎如何查看

  • 使用 SELECT 确认会话存储引擎
#查询默认存储引擎
root@localhost:(none)>select @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| InnoDB                   |
+--------------------------+
  • 使用 SHOW 确认每个表的存储引擎
#查看表的存储引擎
root@localhost:world>SHOW CREATE TABLE city\G
*************************** 1. row ***************************
       Table: city
Create Table: CREATE TABLE `city` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` char(35) NOT NULL DEFAULT '',
  `CountryCode` char(3) NOT NULL DEFAULT '',
  `District` char(20) NOT NULL DEFAULT '',
  `Population` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  KEY `CountryCode` (`CountryCode`),
  CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) REFERENCES `country` (`Code`)
) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

root@localhost:world>show table status like 'countrylanguage'\G
*************************** 1. row ***************************
           Name: countrylanguage
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 984
 Avg_row_length: 99
    Data_length: 98304
Max_data_length: 0
   Index_length: 65536
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2023-07-24 10:46:44
    Update_time: NULL
     Check_time: NULL
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: 
        Comment: 
1 row in set (0.00 sec)

root@localhost [world] >show table status like 'city';
+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-------------------+----------+----------------+---------+
| Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time         | Update_time | Check_time | Collation         | Checksum | Create_options | Comment |
+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-------------------+----------+----------------+---------+
| city | InnoDB |      10 | Compact    | 4188 |             97 |      409600 |               0 |       212992 |         0 |           4080 | 2023-07-27 14:13:26 | NULL        | NULL       | latin1_swedish_ci |     NULL |                |         |
+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-------------------+----------+----------------+---------+
  • 使用 INFORMATION_SCHEMA 确认每个表的存储引擎
#查看表的存储引擎
root@localhost:world>select table_name, engine from information_schema.tables where table_name = 'city' and table_schema = 'world'\G
*************************** 1. row ***************************
table_name: city
    engine: InnoDB
1 row in set (0.00 sec)

存储引擎设置

1)在启动配置文件中设置服务器存储引擎
#在配置文件的[mysqld]标签下添加
[mysqld]
default-storage-engine=<Storage Engine>

2)使用 SET 命令为当前客户机会话设置
#在MySQL命令行中临时设置
SET @@storage_engine=<Storage Engine>

3)在 CREATE TABLE 语句指定
#建表的时候指定存储引擎
root@localhost:(none)>create table hg.ccyq(id int)engine myisam;
root@localhost:(none)>show create table hg.ccyq;
+-------+----------------------------------------------------------------------------------------+
| Table | Create Table                                                                           |
+-------+----------------------------------------------------------------------------------------+
| ccyq  | CREATE TABLE `ccyq` (
  `id` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
+-------+----------------------------------------------------------------------------------------+

修改表存储引擎

root@localhost:(none)>alter table hg.ccyq engine=innodb;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

root@localhost:(none)>show create table hg.ccyq;
+-------+----------------------------------------------------------------------------------------+
| Table | Create Table                                                                           |
+-------+----------------------------------------------------------------------------------------+
| ccyq  | CREATE TABLE `ccyq` (
  `id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+----------------------------------------------------------------------------------------+

企业项目案例

项目背景:

公司原有的架构:一个展示型的网站,LAMT,MySQL5.1.77版本(MYISAM),50M数据量。

小问题不断:

1、表级锁:对表中任意一行数据修改类操作时,整个表都会锁定,对其他行的操作都不能同时进行。

2、不支持故障自动恢复(CSR):当断电时有可能会出现数据损坏或丢失的问题。

如何解决:

1、提建议将现有的MYISAM引擎替换为Innodb,将版本替换为5.6.38

1)如果使用MYISAM会产生”小问题”,性能安全不能得到保证,使用innodb可以解决这个问题。

2)5.1.77版本对于innodb引擎支持不够完善,5.6.38版本对innodb支持非常完善了。

2、实施过程和注意要素

InnoDB特性——表空间

img

共享表空间

5.5版本以后出现共享表空间概念

表空间的管理模式的出现是为了数据库的存储更容易扩展

img

共享表空间存储:

1)undo事务日志

2)系统数据

3)临时表

共享表空间切割:

mysql> show variables like '%path%';
+----------------------------------+------------------------+
| Variable_name                    | Value                  |
+----------------------------------+------------------------+
| innodb_data_file_path            | ibdata1:12M:autoextend |
| innodb_temp_data_file_path       | ibtmp1:12M:autoextend  |
| sha256_password_private_key_path | private_key.pem        |
| sha256_password_public_key_path  | public_key.pem         |
| ssl_capath                       |                        |
| ssl_crlpath                      |                        |
+----------------------------------+------------------------+
2023-07-28 10:34:18 74867 [ERROR] InnoDB: Data file ./ibdata1 is of a different size 768 pages (rounded down to MB) than specified in the .cnf file 3200 pages!

768为页容量
所以需要768*16/1024=12M 所以ibdata1需要设置成12M

独立表空间

存储:表中的真实数据

查看独立表空间是否开启

mysql> show variables like '%per_table%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+

[root@db03 ~]# ll /app/mysql/data/world/city.*
/app/mysql/data/world/city.frm
/app/mysql/data/world/city.ibd

企业案例

可以写简历 恢复表空间

在没有备份数据的情况下,突然断电导致表损坏,打不开数据库。

出现故障

mysql> use world;
mysql> show tables;
+-----------------+
| Tables_in_world |
+-----------------+
| city            |
| country         |
| countrylanguage |
+-----------------+

mysql> select * from city;
ERROR 1146 (42S02): Table 'world.city' doesn't exist

恢复步骤(思路)

# 1.准备新环境
cd /app/mysql/scripts
./mysql_install_db --basedir=/app/mysql --datadir=/app/mysql/data

# 2.建库
mysql> create database world;

# 3.找开发要建表语句
CREATE TABLE `city_new` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` char(35) NOT NULL DEFAULT '',
  `CountryCode` char(3) NOT NULL DEFAULT '',
  `District` char(20) NOT NULL DEFAULT '',
  `Population` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  KEY `CountryCode` (`CountryCode`)
) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1;
# 4.创建表
CREATE TABLE `city_new` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` char(35) NOT NULL DEFAULT '',
  `CountryCode` char(3) NOT NULL DEFAULT '',
  `District` char(20) NOT NULL DEFAULT '',
  `Population` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  KEY `CountryCode` (`CountryCode`)
) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1;

# 5.删除新表的表空间
mysql> alter table city_new discard tablespace;

# 6.将旧表的表空间拷贝到新表下
[root@db04 world]# cp -a city.ibd city_new.ibd

# 7.导入新表的表空间
mysql> alter table city_new import tablespace;

# 8.删除旧表
[root@db02 world]# rm -f city.frm city.ibd

# 9.修改表名
mysql> alter table city_new rename city;

# 9.9挂维护页

# 10.应用割接
- 开发改代码,修改连接数据库的IP地址
- 将新环境做一个全备,mysqldump -B world > /tmp/wd.sql

# 11.binlog截取新增数据,恢复到旧环境

# 12.取消维护页

InnoDB核心特性——事务

事务 伴随着交易

事务主要针对DML语句(insert、update、delete)

事务特性:

A:原子性:将一个事务视为一个单元,要么全部成功,有一条失败,就全部回滚

C:一致性:事务执行之前和事务执行之后,状态保持一致

I:隔离性:事务与事务之间互相隔离

D:持久性:当事务被提交后,永久写入磁盘

img

事务的生命周期

# 成功的事务:
begin;
DML
DML
DML
commit;

# 失败的事务
begin;
DML
DML
DML
rollback;

事务控制语句

begin; start transaction; // 开启一个事务

savepoint; // 将事务保存在某一状态
mysql> savepoint zls_4000;

rollback to savepoint; // 回到指定的位置点
mysql> rollback to savepoint zls_4000;

release savepoint; // 删除位置点
mysql> release savepoint zls_4000;
commit; // 提交事务
rollback; // 回滚事务

## 设置
SET AUTOCOMMIT:为当前连接禁用或启用默认 autocommit 模式

vim /etc/my.cnf
[msyqld]
autocommit=0

MySQL在默认情况下,只要执行一个DML语句,就会自动开启一个事务

事务的隐式提交

1)在事务执行期间,如果执行了begin,开启下一个事务,自动提交上一个事务。
2)在事务执行期间,如果执行了DDL、DCL也会自动提交事务
3)在事务执行期间,如果执行锁表语句 lock,unlock也会自动提交上一个事务
4)load data in file,做备份
5)select for update 自动提交事务
6)在autocommit开启的时候,自动提交事务

image-20230905211927124

MySQL 数据写入特性:WAL(日志优先写)

MySQL 数据,包括事务提交后,不是针对把所有数据都写入磁盘持久化,而是优先记录日志

MySQL 数据写入磁盘,就是将内存中的数据,写入到独立表空间中(.ibd 文件)

undo: 不做

image-20230905212049117

image-20230905212120828

image-20230905212153159

innodb 核心特性 —— 锁

锁粒度:行级锁

共享锁:在一个事务执行期间,不阻塞查询操作

排它锁:在一个事务执行期间,阻塞其他修改操作

乐观锁:谁先提交,以谁为准

悲观锁:以事务开启为准,谁先执行修改操作,其他人查询会被阻塞

innodb 核心特性 ——MVCC 多版本并发控制

共享锁:在一个事务执行期间,不阻塞查询操作

排它锁:在一个事务执行期间,阻塞其他修改操作

乐观锁:谁先提交,以谁为准

1)只阻塞修改类操作,不阻塞查询类操作

2)乐观锁的机制(谁先提交谁为准)

事务的隔离级别

mysql> show variables like '%iso%';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
| tx_isolation          | REPEATABLE-READ |
+-----------------------+-----------------+

MySQL隔离级别:
1) RU: read uncommit 未提交读
   允许事务查看其他事务所进行的未提交更改
   RC解决了脏读的问题

2) RC: read commit 提交读 
   允许事务查看其他事务所进行的已提交更改
   RR解决了幻读
   RR解决了不可重复读

3) RR: repeatable read 可重复读(默认隔离级别)
   确保每个事务的 SELECT 输出一致

4) SERIALIZABLE 串形化级别
   将一个事务的结果与其他事务完全隔离

触发器

MySQL 触发器是与数据库中的表相关联的一种特殊类型的存储过程。当满足特定的条件时,触发器会自动执行,并且可以在表上执行 INSERT、UPDATE 或 DELETE 操作之前或之后执行自定义的逻辑。

以下是创建和使用 MySQL 触发器的一般步骤:

\1. 创建一个新的触发器:

CREATE TRIGGER trigger_name
BEFORE/AFTER INSERT/UPDATE/DELETE ON table_name
FOR EACH ROW
BEGIN
    -- 触发器逻辑
END;
  • trigger_name 是触发器的名称,您可以根据需要选择适当的名称。
  • BEFORE/AFTER 关键字指定触发器在操作之前还是之后执行。
  • INSERT/UPDATE/DELETE 表示触发器所针 [Something went wrong, please try again later.]

视图 view

mysql View

视图是 mysql 数据库中存放数据的一个接口

介绍

视图是存放数据的一个接口,也可以说是虚拟的表。这些数据可以是从一个或几个基本表(或视图)的数据。也可以是用户自已定义的数据。其实视图里面不存放数据的,数据还是放在基本表里面,基本表里面的数据发生变动时,视图里面的数据随之变动。

作用

1,mysql view 让查询变得很清晰,视图中存放的数据就是我们所要的数据,并且可以简化用户操作。

2,mysql view 让数据更安全,视图中的数据,不存在视图中,还是在基本表里面,通过视图这层关系,我们可以有效的保护我们的重要数据

类型

mysql 的视图有三种类型:MERGE、TEMPTABLE、UNDEFINED。如果没有 ALGORITHM 子句,默认算法是 UNDEFINED(未定义的)。算法会影响 MySQL 处理视图的方式。

1,MERGE,会将引用视图的语句的文本与视图定义合并起来,使得视图定义的某一部分取代语句的对应部分。

2,TEMPTABLE,视图的结果将被置于临时表中,然后使用它执行语句。

3,UNDEFINED,MySQL 将选择所要使用的算法。如果可能,它倾向于 MERGE 而不是 TEMPTABLE,这是因为 MERGE 通常更有效,而且如果使用了临时表,视图是不可更新的。

3.MySQL 故障,怎么产生如何解决

# 脏读 RU
一个读取操作读取到了其它未提交事务中的数据。
就是一个事务读取了其它事务正在修改的数据而且这个数据还没有被提交。
## 解决方法
### 1.使用事务
在MySQL中,使用事务可以解决脏读的问题。事务可以将多个操作组合在一起,然后一起提交或一起回滚。这就保证了读取操作只能读到已提交的数据。
### 2.使用锁
除了使用事务,还可以使用锁来解决脏读的问题。MySQL提供了两种类型的锁:共享锁和排他锁。共享锁是指多个事务可以同时读取同一份数据,而排他锁是指只有一个事务可以修改这份数据。

# 幻读 RC
在事务提交之后,其他事务立马可以查询导数据的变化,就像是出现了幻觉一样
事务A按照一定条件进行数据读取,期间事务B插入了相同搜索条件的新数据,事务A再次按照原先条件进行读取操作修改时,发现了事务B新插入的数据称之为幻读。
## 解决方法
加间隙锁(如果当前和快照读均存在的情况下)。
采用mysql 5.6之后的版本和 默认的隔离级别 RR ,启动A、B两个事务对比,阿拉伯数字递增代表事务执行的时间顺序,比如 1,2,3,4.......,模拟数据库执行(前提是数据库有两条数据)

# 不可重复读 RC
指一个事务提交之后,读取另一个提交后的结果发生了变化
事务A首先读取了一条数据,然后执行逻辑的时候,事务B将这条数据改变了,然后事务A再次读取的时候,发现数据不匹配了,就是所谓的不可重复读了。
## 解决方法
1.使用事务隔离级别
MySQL使用的四种事务隔离级别:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。修改隔离级别可以解决不可重复读问题。

2.使用悲观锁(排他锁)
悲观锁在读取数据时会给数据加上锁,直到事务结束才释放锁。在对数据进行更新时,其他事务无法读取该数据,避免了不可重复读问题。

3.使用乐观锁(版本锁)
乐观锁通过给记录加版本号,解决多个事务同时读取并修改同一条数据时发生的冲突问题。当事务提交更新请求时,如果发现该记录的版本与更新前不一致,就认为出现了重复读问题。

4.使用MVCC
多版本并发控制(Multi-Version Concurrency Control,简称MVCC)是一种常用的解决并发事务问题的技术。MVCC在读取数据时会分配一个版本号,每个事务读取的都是自己所在的版本。当数据被修改时,会生成新的版本号,保证了不同事务读取的是不同版本的数据,从而避免了重复读问题。