0502事务原理-InnoDB引擎-MySQL-数据库

news2024/11/28 18:41:03

1 概述

事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有操作作为一个整体一起向系统提交或者撤销操作请求,即这些操作要么同时成功,要么同时失败。

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

2 事务原理

在这里插入图片描述

事务的原子性、一致性和持久性是由两类日志,redo log和undo log保证的;事务的隔离性则由锁和mvcc保证。

2.1 redo log 和 持久性

重做日志,记录的是事务提交时数据页的物理修改,用来实现事务的持久性。

该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log file),前者在内存中,后者在磁盘中。当事务提交之后会把所有修改信息保存到该日志文件中,用于在刷新脏页到磁盘发生错误时,进行数据恢复使用。

在这里插入图片描述

  • 没有redo log时的更新流程

数据修改,事务提交后,缓冲区数据直接刷新到磁盘,已经通知客户端事务提交成功。但是刷新脏页数据出现错误,导致数据的不一致。

在这里插入图片描述

  • redo log 更新流程

事务提交后,首先redo log buffer保存数据页的变化,更新到磁盘redo log 文件。然后缓冲区数据变更刷新到磁盘,如果执行正常,那么磁盘中redo log 文件就不需要关注;如果刷新脏页发生错误,通过redo log来恢复数据。这种机制称为WAL(write-ahead logging),优先记录日志。日志文件iblogfile0与iblogfile1循环使用,定期清理。

MySQL的redo log(重做日志)是用于保证事务的持久性的一种机制。它记录了所有对数据库所做的修改操作,以便在系统故障或重启后进行恢复。下面是MySQL redo log的原理:

  1. 重做日志的结构:MySQL的重做日志是由一系列固定大小的日志文件组成,通常被称为redo log文件组。每个redo log文件都被划分为多个大小相等的日志块(log block)。在每个日志块中,记录了数据库的修改操作。
  2. 写入过程:当执行一个事务的修改操作时,MySQL首先将这些修改操作记录到内存中的重做日志缓冲区(redo log buffer),然后异步地将缓冲区中的日志写入到磁盘上的重做日志文件中。这个过程称为"write-ahead logging"(先写日志,再写磁盘)。在事务提交之前,只需要将重做日志写入到磁盘,而不需要将所有的数据修改都写入到磁盘。
  3. 持久化:重做日志的写入是采用顺序写(sequential write)方式,这样可以提高写入性能。写入磁盘的过程中,MySQL使用了一种叫做"write sync"的策略,即将重做日志文件的数据强制刷新到磁盘上的持久存储,以保证数据的持久性。在写入磁盘之前,MySQL还会将日志数据按照一定的顺序进行分组,以减少磁盘IO的次数,提高性能。
  4. 重做日志的应用:当系统发生崩溃或重启时,MySQL会通过重做日志来进行数据库的恢复。在数据库启动时,MySQL会读取最后一个完整的事务日志块,并从中恢复出未完成的事务。然后,MySQL会根据重做日志的记录顺序,重新执行日志中的操作,将数据库恢复到崩溃前的状态。

重做日志的存在使得MySQL能够在系统故障或重启后保持事务的持久性。通过将事务的修改操作先记录到重做日志中,而不是立即写入磁盘,MySQL实现了较高的写入性能。同时,通过顺序写和写入磁盘前的分组操作,也提高了重做日志的写入效率。这种机制保证了MySQL的数据一致性和可靠性。

2.2 undo log 和原子性

回滚日志,用于记录数据被修改前的信息,作用包含两个:提供回滚和MVCC(多版本并发控制)。

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。

MySQL的undo log(撤销日志)是用于实现事务的回滚和MVCC(多版本并发控制)的一种机制。它记录了对数据库进行修改的旧值,以便在事务回滚或读取旧版本数据时使用。下面是MySQL undo log的原理:

  1. 撤销日志的结构:MySQL的撤销日志是以逻辑日志的形式存在的,每个事务都有自己的撤销日志。在每个事务开始时,MySQL会为该事务分配一个撤销日志的段(undo log segment),其中包含多个撤销日志块(undo log block)。每个撤销日志块都存储了对应事务的修改操作。
  2. 写入过程:当执行一个事务的修改操作时,MySQL会在撤销日志中记录对应的旧值。这些修改操作首先会被写入内存中的撤销日志缓冲区(undo log buffer),然后异步地将缓冲区中的日志写入到磁盘上的撤销日志块中。与重做日志不同,撤销日志的写入是在事务执行过程中进行的,而不是在事务提交之前。
  3. 回滚操作:当事务需要回滚时,MySQL会根据事务的撤销日志来进行回滚操作。通过读取撤销日志中的旧值,MySQL可以将数据恢复到事务开始之前的状态。回滚操作是通过撤销事务执行过程中所做的修改来实现的。
  4. MVCC支持:MySQL使用撤销日志来实现MVCC(多版本并发控制)。在读取数据时,如果事务需要读取一个已经被其他事务修改的数据,MySQL会根据撤销日志中的旧值创建一个新的数据版本(数据快照),供该事务读取。这样可以实现事务之间的隔离性,避免读取到未提交的修改。

撤销日志在MySQL中起到了重要的作用,它保证了事务的回滚能力和MVCC的支持。通过记录旧值和撤销操作,撤销日志使得MySQL能够回滚事务的修改,恢复到事务开始前的状态。同时,通过撤销日志的利用,MySQL实现了MVCC,提供了高并发的数据读取和隔离性。

3 MVCC

3.1 基本概念

当前读:读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录加锁。比如select ... lock in share mode ,select ... for update ,update、insert、delete都是当前读。

当前读(Current Read)是数据库事务隔离级别中的一种读取数据的方式。在当前读中,事务读取的是最新提交的数据版本,而不考虑正在执行的事务对数据所做的修改。

在当前读中,如果某个事务在读取某个数据行时,发现该数据行已经被其他事务修改但尚未提交,当前读会等待该事务完成并获取最新的数据版本后再读取。这种读取方式保证了事务读取到的数据是最新提交的数据。

当前读的特点如下:

  1. 读取最新提交的数据:当前读忽略了正在执行的事务对数据所做的修改,直接读取最新提交的数据版本。
  2. 阻塞等待:如果当前读发现某个数据行正在被其他事务修改但尚未提交,它会等待该事务完成并获取最新的数据版本后再进行读取。这可能导致当前读的阻塞等待,直到需要读取的数据行可用。
  3. 读取一致性数据:当前读保证事务读取的数据是一致性的,即读取的是最新提交的数据版本,而不会读取到其他事务正在修改但尚未提交的数据。

当前读适用于一些对数据的实时性要求较高的场景,如查询实时统计数据、显示最新的库存信息等。但是需要注意,当前读可能会导致更多的阻塞等待,对并发性能产生影响。因此,在选择隔离级别和读取方式时,需要综合考虑应用的实际需求和并发性能的平衡。

快照读:简单的select(不加锁)就是快照读,读取的是数据记录的可见版本,有可能是历史版本,不加锁,是非阻塞读取。

快照读(Snapshot Read)是数据库事务隔离级别中的一种读取数据的方式。在快照读中,事务读取的是一个一致性的数据快照,即读取事务开始时数据库中的数据版本,并在整个事务过程中保持不变,不受其他事务的修改影响。

快照读的特点如下:

  1. 读取一致性数据快照:快照读保证事务读取的数据是在事务开始时数据库中的一致性数据版本,并在整个事务过程中保持不变。即使其他事务对数据进行了修改或提交,快照读也不会读取到这些变更。
  2. 不阻塞等待:快照读不会等待其他事务的锁或提交操作,它读取的是已经存在的数据版本,并不关心其他事务对数据的修改。因此,快照读不会阻塞等待其他事务的完成。
  3. 提供事务的一致性视图:快照读为事务提供了一个一致性的数据视图,事务可以在整个事务过程中使用该视图进行读取操作,而不会受到其他并发事务的修改干扰。

快照读适用于一些不要求读取最新数据的场景,如生成报表、数据分析等。由于快照读不会阻塞等待其他事务,因此可以提高并发性能。然而,需要注意的是,由于快照读读取的是一致性数据快照,可能会导致读取到已经过时的数据。因此,在选择隔离级别和读取方式时,需要根据应用的实际需求来确定是否使用快照读。

演示:

开启2个客户端,2个客户端都开启事务。客户端1简单读,客户端2修改一条记录,客户端再次读取数据。

在这里插入图片描述

不管客户端2事务修改记录未提交还是提交事务,客户端1都是快照读,读取的数据一致。如果客户端想要读取数据的最新记录,需要执行当前读。

MVCC(Multi-Version Concurrency Control)是一种用于实现并发控制的数据库技术。它在多用户并发访问数据库时,通过创建和管理多个数据版本,实现了高并发性和数据一致性的平衡。MVCC常用于支持事务隔离级别为"可重复读"的数据库系统,如MySQL的InnoDB存储引擎。

​ MVCC的具体实现,还需要依赖于数据库记录中的三个隐藏字段、undo log日志和readView。

3.2 隐藏字段

如何查看表中隐藏字段呢?通过ibd2sdi命令查看表空间文件.ibd,命令使用可以参考msyql官方文档<https://dev.mysql.com/doc/refman/8.0/en/ibd2sdi.html>或者参考下面链接5.

ibd2sdi stu.ibd
       // 部分字段相关内容如下所示
{
"name": "DB_TRX_ID",
      "type": 10,
      "is_nullable": false,
      "is_zerofill": false,
      "is_unsigned": false,
      "is_auto_increment": false,
      "is_virtual": false,
      "hidden": 2,
      "ordinal_position": 4,
      "char_length": 6,
      "numeric_precision": 0,
      "numeric_scale": 0,
      "numeric_scale_null": true,
      "datetime_precision": 0,
      "datetime_precision_null": 1,
      "has_no_default": false,
      "default_value_null": true,
      "srs_id_null": true,
      "srs_id": 0,
      "default_value": "",
      "default_value_utf8_null": true,
      "default_value_utf8": "",
      "default_option": "",
      "update_option": "",
      "comment": "",
      "generation_expression": "",
      "generation_expression_utf8": "",
      "options": "",
      "se_private_data": "table_id=1169;",
      "engine_attribute": "",
      "secondary_engine_attribute": "",
      "column_key": 1,
      "column_type_utf8": "",
      "elements": [],
      "collation_id": 63,
      "is_explicit_collation": false
  },
  {
      "name": "DB_ROLL_PTR",
      "type": 9,
			...
  }
    
  • DB_TRX_ID:最近修改事务ID,记录插入这条记录或者最后一次修改该记录的事务ID。

db_trx_id 是 MySQL InnoDB 存储引擎中的一个系统变量,用于表示当前事务的唯一标识符(Transaction ID)。每个事务在 InnoDB 存储引擎中都会被分配一个唯一的 db_trx_id 值。

db_trx_id 的作用是用于事务管理和并发控制。它主要用于以下方面:

  1. 事务标识:db_trx_id 作为事务的标识符,用于唯一标识每个正在执行的事务。通过 db_trx_id,可以识别和区分不同的事务。
  2. 并发控制:db_trx_id 在并发控制机制中起着重要的作用。通过比较不同事务的 db_trx_id 值,可以确定事务的先后顺序,并根据事务的隔离级别进行相应的读取操作。
  3. MVCC(多版本并发控制):在 InnoDB 存储引擎中,db_trx_id 与 MVCC 搭配使用。每个数据行都会记录其被修改的事务ID范围(最小和最大的 db_trx_id 值)。通过比较事务的 db_trx_id 值和数据行的事务ID范围,可以确定事务是否可以读取该数据行,以实现事务的隔离性和一致性。

总之,db_trx_id 是 InnoDB 存储引擎中用于标识事务和实现并发控制的重要变量。它在事务管理、并发控制和MVCC机制中起着关键的作用。

  • DB_ROLL_PTR:回滚指针,执行该记录的上一个版本,用于配合undo log。

db_roll_ptr 是 MySQL InnoDB 存储引擎中的一个系统变量,表示回滚段指针(Rollback Segment Pointer)。它用于管理事务的回滚段。

回滚段是 InnoDB 存储引擎用于实现事务回滚操作的数据结构。当事务执行修改操作时,InnoDB会将旧数据的备份存储在回滚段中,以便在事务回滚时恢复数据。db_roll_ptr 存储了当前回滚段的指针位置,用于标识回滚段中的数据。

db_roll_ptr 的作用如下:

  1. 回滚段管理:db_roll_ptr 用于管理回滚段的状态和位置。它指向当前正在使用的回滚段,以便在事务回滚时可以快速定位回滚段并进行数据恢复。
  2. 事务回滚:当事务需要回滚时,db_roll_ptr 会指向回滚段中存储的旧数据,用于将数据恢复到事务开始之前的状态。
  3. 并发控制:db_roll_ptr 在并发控制中起着重要的作用。通过比较不同事务的 db_roll_ptr 值,可以确定事务的先后顺序,并根据事务的隔离级别进行相应的读取操作。

总之,db_roll_ptr 是 InnoDB 存储引擎中用于管理回滚段和实现事务回滚的系统变量。它在事务回滚、并发控制和MVCC机制中扮演着重要的角色。

  • DB_ROW_ID:隐藏主键,当表没有指定主键的时候,系统会自动为每个表记录生成一个隐藏字段db_row_id,用来唯一标志一行。
隐藏字段描述
DB_TRX_ID最近修改事务ID,记录插入这条记录或者最后一次修改该记录的事务ID
DB_ROLL_PTR回滚指针,执行该记录的上一个版本,用于配合undo log
DB_ROW_ID隐藏主键,当表没有指定主键的时候,系统会自动为每个表记录生成一个隐藏字段db_row_id,用来唯一标志一行

3.3 undo log

回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。

当insert的时候,产生的undo log只在回滚的时候需要,在事务提交后,可被立即删除;而update、delete的到时候,产生的undo log日志,不仅在回滚的时候需要,在快照读的时候也需要,不会立即删除。

  • undo log 版本链

在这里插入图片描述

不同事物或者相同事务对同一条记录进行修改,undo log会生成该记录的版本链表,链表表头是最新的旧记录,链表尾部是最早的旧记录。

3.4 readview

3.4.1 简介

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

字段含义
m_ids当前活跃事务ID集合
min_trx_id最小活跃事务id
max_trx_id预分配事务ID,当前活跃事务最大id+1(事务ID自增)
creator_trx_idReadView创建者事务ID

3.4.2 版本链数据访问规则

在这里插入图片描述

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

  • READ COMMITED:在事务每一次执行快照读时生成ReadView;
  • REPEATABLE READ:仅在事务第一次执行快照读时生成ReadView,后续复用该ReadView。

在这里插入图片描述

图片直接截图自视频,其中在事务5子在RC级别下第一次执行快照读的时候,左侧最新的记录即事务4修改那条记录应该还没有的。

在RR隔离级别下,第二次读取会复用第一次快照读生成的ReadView,即读取数据一致的。

在这里插入图片描述

结语

如果小伙伴什么问题或者指教,欢迎交流。

❓QQ:806797785

参考链接:

[1]MySQL数据库视频[CP/OL].2020-04-16.p138-146.

[2]Mysql事务的实现原理之Redo Log的分析

[3]mysql 物理日志之redo log(重做日志)原理和介绍

[4]mysql事务实现的原理(redo log,undo log详解)

[5]ibd2sdi — InnoDB表空间SDI提取实用程序

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/759327.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MiniGPT4系列之一部署篇:在RTX-3090 Ubuntu服务器部署步骤详解

MiniGPT4系列之一部署篇&#xff1a;在RTX-3090 Ubuntu服务器部署步骤详解_seaside2003的博客-CSDN博客 MiniGPT4系列之二推理篇命令行方式&#xff1a;在RTX-3090 Ubuntu服务器推理详解_seaside2003的博客-CSDN博客 MiniGPT4系列之三模型推理 (Web UI)&#xff1a;在RTX-309…

外包软件定制开发中关于沟通障碍及对应解决方案

引言 外包软件定制开发在当今的商业环境中越来越常见。它为公司提供了许多好处&#xff0c;包括降低成本、加速交付和专注于核心业务。然而&#xff0c;沟通障碍常常是外包软件定制开发中的一个重要挑战。由于外包团队和客户位于不同的地理位置、文化和语言差异&#xff0c;沟…

Python 列表 sort()函数使用详解

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 sort函数使用详解 1、升序降序2、sort()和sorted()的区别3、切片排序4、指定排序…

【C++】设计模式-单例模式

目录 一、单例模式 单例模式的三个要点 针对上述三要点的解决方案 常用的两类单例模式 二、懒汉模式实现 1.基本实现 2.锁静态成员析构单例 3.双层检查锁定优化 4.双层检查锁定智能指针 三、饿汉模式实现 1.基础实现 2.嵌套内部类解决内存泄漏 3.智能指针解决内存泄…

一种用于RBF神经网络的新型自适应内核研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

vuejs源码之虚拟dom中的vnode

在虚拟dom中&#xff0c;vnode是比较重要的。 什么是vnode 在vuejs中&#xff0c;有一个Vnode类 使用它可以实例不同类型的vnode实例&#xff0c;而不同类型的vnode实例各自表示不同类型的dom元素。 例如dom元素有文本节点&#xff0c;元素节点&#xff0c;注释节点等。 co…

Spring IoC及DI依赖注入

Spring 1.Spring的含义&#xff1a; Spring 可从狭义与广义两个角度看待 狭义的 Spring 是指 Spring 框架(Spring Fremework) 广义的 Spring 是指 Spring 生态体系 2.狭义的 Spring 框架 Spring 框架是企业开发复杂性的一站式解决方案 Spring 框架的核心是 IoC 容器和 AO…

数据库java中jdbcTemplate的事务问题

1.什么都不设置事务是默认提交的 两次获取的连接是不是一样的 参考文献(重磅): (542条消息) JdbcTemplate的事务控制_jdbctemplate transactionmanager_DayDayUp丶的博客-CSDN博客 PostMapping("/pinYin22")CrossOriginTransactionalpublic String pinYin22(HttpS…

【js实现语言国际化】使用json配置文件实现

需求&#xff1a;使用js让项目实现中文简体、繁体跟英文的切换&#xff0c;实现语言国际化 首先准备三种json配置文件&#xff1a; en.json {"textOne": "Today is Monday","textTwo": "Tomorrow is Tuesday","textThree"…

F#奇妙游(14):F#实现WPF的绑定

WPF中的绑定 绑定在UI开发中是一个非常重要的概念&#xff0c;它可以让我们的UI界面和数据模型之间建立起联系&#xff0c;当数据模型发生变化时&#xff0c;UI界面也会随之变化&#xff0c;反之亦然。这样的好处是显而易见的&#xff0c;我们不需要手动去更新UI界面&#xff…

金智教育IPO过会:计划募资约6亿元,郭超、史鸣杰为实控人

7月13日&#xff0c;深圳证券交易所披露的信息显示&#xff0c;江苏金智教育信息股份有限公司&#xff08;下称“金智教育”&#xff09;获得上市委会议通过。据贝多财经了解&#xff0c;金智教育于2022年6月30日递交上市申请材料&#xff0c;先后递交了6个版本的招股书&#x…

NDK OpenGL与OpenCV实现大眼萌特效

NDK​系列之OpenGL与OpenCV实现大眼萌特效&#xff0c;本节主要是在上一节OpenGL仿抖音极快极慢录制特效视频上增加大眼萌的特效。 OpenGL视频特效系列&#xff1a; NDK OpenGL渲染画面效果 NDK OpenGL离屏渲染与工程代码整合 NDK OpenGL仿抖音极快极慢录制特效视频 NDK O…

通讯录实现

普通版 需求 通讯录可以用来存储1000个人的信息&#xff0c;每个人的信息包括&#xff1a;姓名、性别、年龄、电话、住址 提供方法&#xff1a; 添加联系人信息删除指定联系人信息查找指定联系人信息修改指定联系人信息显示所有联系人信息清空所有联系人以名字排序所有联系…

【Linux后端服务器开发】UDP协议

目录 一、端口号 二、UDP报头格式 三、UDP的特点 四、UDP协议实现网络聊天群 一、端口号 端口号port标识了一个主机上进行通信的不同的应用程序。 0 ~ 1023&#xff1a;系统端口号&#xff0c;HTTP、FTP、SSH等这些广为使用的应用层协议&#xff0c;它们的端口号都是固定…

Windows软件开发常用技巧总结

本文总结了本人在日常工作学习中遇到的问题及其解决方法&#xff0c;没有固定的涉及领域 目的就是为了在下一次遇到类似问题的时候方便查找&#xff0c;从而快速解决问题 本文不定时更新~ 目录 Windows使用 如何实现桌面图标随意排列 文件资源管理器相关 显示隐藏文件 修改…

Linux--获取最近一次的进程退出码:echo $?

举例&#xff1a; #include <stdio.h> int main() { printf("hello world,pid: %d,ppid: %…

JavaFx 用户界面控件3——TableView

1.表格视图 TableView ableView是JavaFX提供的一个强大的控件&#xff0c;可以用于显示表格数据。它通过为TableView设定items属性&#xff08;存储行数据的ObservableList对象&#xff09;和列属性&#xff08;TableColumn对象&#xff09;来完成数据填充与展示。 以下是一个…

如何做一线leader

文章目录 道领导力五个层次关键&#xff1a;信任 处事原则 术避坑指南事急则乱员工沟通向上管理人才招聘人才培养裁人员工关怀 道 领导力 五个层次 职位 当面交代事情&#xff0c;观察眼神、语气。反复确认有没有问题&#xff0c;如果有可以及时讨论策略&#xff0c;准备资源…

IDEA连接达梦数据库

在 IntelliJ IDEA 中连接达梦数据库&#xff0c;可以按照以下步骤进行操作&#xff1a; 1. 打开 IntelliJ IDEA&#xff0c;进入项目。 2. 在顶部菜单栏选择 "View" -> "Tool Windows" -> "Database"&#xff0c;打开数据库工具窗口。 3.…

自旋锁的优势和特点

ucos为何没自旋锁&#xff1f; UC/OS是一个适用于嵌入式系统的实时操作系统&#xff0c;它的设计目标是提供一种轻量级的任务调度和同步机制。相比于一般的操作系统&#xff0c;UC/OS在实现上更加精简&#xff0c;因此并没有像Linux那样的完整的锁机制。 UC/OS提供了一些基本…