Mysql存储引擎和事物

举报
幼儿园老大* 发表于 2025/01/31 22:06:56 2025/01/31
【摘要】 存储引擎实际执行对数据库数据的存取。目前 MySQL 默认使用 InnoDB 引擎。相比于过去使用 MyISAM 引擎,有以下几个优势:索引:数据文件本身是主索引。外键:支持外键。事务:添加本地日志,支持安全恢复;支持行级锁,提高并发度。并发:支持多版本并发控制,提升性能。索引存储结构MySQL 数据库使用以下两种数据结构存储和查找数据:B+ 树:(默认)适用于连续查询多条数据。哈希表:适用...

存储引擎

实际执行对数据库数据的存取。目前 MySQL 默认使用 InnoDB 引擎。相比于过去使用 MyISAM 引擎,有以下几个优势:

  1. 索引:数据文件本身是主索引。
  2. 外键:支持外键。
  3. 事务:添加本地日志,支持安全恢复;支持行级锁,提高并发度。
  4. 并发:支持多版本并发控制,提升性能。

索引

存储结构

MySQL 数据库使用以下两种数据结构存储和查找数据:

  1. B+ 树:(默认)适用于连续查询多条数据。
  2. 哈希表:适用于查询单条数据。

索引类型

索引名称|索引类型|字段类型|备注 -|-|- PRIMARY KEY|主索引|主键|字段值不能重复,也不能为空。 INDEX|普通索引|自定义字段|无,效率低。 UNIQUE|唯一索引|自定义字段|字段值不能重复,效率高。 FULLTEXT|文本索引|自定义字段|无,用于文本检索。

  • 主索引

在 InnoDB 存储引擎中数据文件本身就是主索引(聚簇索引):数据以 B+ 树形式存储,根据主键值进行排序。

我们可以为其他字段建立辅助索引(非聚簇索引),以提高对字段的查询速度,但同时会降低表的更新速度。在辅助索引中记录主键值而不是字段地址:根据辅助索引查找后,仍需要根据主键值在主索引中查询数据。

  • 组合索引

索引内可以包含多个字段,N 个字段的组合索引实际建立了 N 个索引。

对 a/b/c 三个字段建立的组合索引,实际会先在 a 索引中查找,再到 a/b 索引中查找,最后在 a/b/c 索引中查找。

视图

视图是一个虚拟表,不实际存储数据。其内容会通过查询其他表得到,在引用视图时动态生成。

  1. 权限管理:表的权限管理不能限制到具体的行和列,但通过视图则可以限制用户能得到的结果集。
  2. 数据独立:表的结构发生变化,不会对用户使用视图查询到的数据产生影响。

外键

从表通过外键关联到主表的主键,建立数据表之间的关系。

  • 优点:保障数据的一致性和完整性。
  • 缺点:增加数据之间的耦合度,难以集群。因此不推荐使用外键。

删除策略

对主表的数据进行 UPDATE/DELETE 操作时,将会会影响到关联的从表。

外键模式 删除策略
RESTRICT (默认)从表有相关数据时,主表不能更新/删除。
CASCADE 主表记录更新/删除时,从表相关记录也会被更新/删除。
SET NULL 主表数据更新/删除时,从表相关记录的外键值被设为 NULL。
NO ACTION 啥也不做

日志

当数据库数据发生更改时,用日志记录数据库操作。当发生错误或者冲突时,可以进行回滚。保证数据的一致性。

bin log 归档日志

最开始 MySQL 并没与 InnoDB 引擎,其他存储引擎只有通用的 bin 日志用来归档(位于 server 层)。

InnoDB 引擎完成主存数据更新后向执行器提交,由 bin 日志记录操作。如果主存数据已更新,且 bin 日志没有被写入时数据库崩溃,后续进行机器备份的时候就会丢失原有数据。这导致数据没有安全恢复的能力:一旦数据库发生异常重启,之前提交的记录都会丢失。

redolog 重做日志

MySQL 引入 InnoDB 引擎后,自带了 redo 日志。用于数据库发生异常重启时系统记录的恢复。

  1. InnoDB 引擎完成主存数据更新但还未提交时,由 redo 日志记录操作并进入 prepare 状态。
  2. InnoDB 引擎向执行器提交时,由 bin 日志记录操作。
  3. 提交完成后执行器通知 InnoDB 引擎,redo 日志进入 commit 状态。

如果 bin 日志没有被写入时数据库崩溃,后续进行机器备份的时候就会按照 redo 日志恢复数据。

如果 bin 日志已经写完但 redo 日志还处于 prepare 状态时数据库崩溃。MySQL 会判断 redo 日志是否完整,如果完整就立即提交。否则再判断 bin 日志是否完整,如果完整就提交 redo 日志,不完整就回滚事务。这样就解决了数据一致性的问题。


事务

事务是逻辑上的一组操作,要么都执行,要么都不执行。保障数据之间的同步。

事务特性 ACID

  • 原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
  • 一致性: 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;
  • 隔离性: 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
  • 持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

并发事务潜在问题

  • 丢失修改

事务(T1)修改数据的过程中,另一个并发事务(T2)也修改了该数据。导致事务(T1)对数据的修改丢失。

  • 脏读

事务(T1)修改数据但还未写入数据库时,另一个并发事务(T2)使用了该数据。导致事务(T2)读取数据可能是不正确的。

  • 不可重复读

事务(T1)两次读取数据的过程中,另一个并发事务(T2)修改了该数据。导致事务(T1)两次读取数据的结果不同。

  • 幻读

事务(T1)两次读取数据集合的过程中,另一个并发事务(T2)插入或删除了部分数据。导致事务(T1)两次读取数据的结果不同。

数据锁

存储引擎通过给数据加锁来保障事务性。MyISAM 引擎只支持表级锁,而 InnoDB 存储引擎支持行级锁和表级锁,默认为行级锁。

  • 表级锁:对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。但触发锁冲突的概率最高,并发度低。

  • 行级锁:只针对当前操作的数据行加锁。大大减少数据库操作的冲突,并发度高。但加锁的开销也最大,可能会出现死锁。

InnoDB支持三种行锁定方式:

  • 间隙锁:锁定索引的记录间隙,确保索引记录的间隙不变。

Next-Key Lock 是行级锁和间隙锁的组合使用。当 InnoDB 扫描索引记录的时候,会首先对索引记录加上行锁(Record Lock),再对索引记录两边的间隙加上间隙锁(Gap Lock)。其他事务就不能在这个间隙修改或者插入记录。间隙锁是针对事务隔离级别为可重复读或以上级别,可以有效防止幻读的发生。

事务隔离级别

  • READ-UNCOMMITTED(RU) 读取未提交

事务进行读操作时允许其他事务访问,事务进行写操作将会禁止其他事务写。

  • READ-COMMITTED(RC) 读取已提交

事务进行读操作时允许其他事务访问,事务进行写操作将会禁止其他事务读写。

  • REPEATABLE-READ(RR) 可重复读

事务进行读操作时会禁止其他事务写,事务进行写操作将会禁止其他事务读写。

  • SERIALIZABLE 可串行化

事务进行读写操作时,都会禁止其他事务读写。

隔离级别 丢失修改 脏读 不可重复读 幻读
READ-UNCOMMITTED ×
READ-COMMITTED × ×
REPEATABLE-READ × × ×
SERIALIZABLE × × × ×
  1. InnoDB 存储引擎默认支持的隔离级别是 REPEATABLE-READ(RR) ,且 InnoDB 在该事务隔离级别下使用 Next-Key Lock 锁算法,可以避免幻读。
  2. InnoDB 存储引擎在分布式事务情况下一般会用到 SERIALIZABLE 隔离级别。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。