mysql--事务基础

事务概述

事务是一组逻辑操作单元,使数据从一种状态变换到另一种状态。

事务的特性

  • 原子性:事务是一个不可分割的工作单位,要么全部提交,要么全部回滚失败。通过undo日志保证
  • 一致性:事务执行前后从一个合法状态(满足预定约束的状态)变换到另一个合法状态,通过undo日志保证
  • 隔离性: 一个事务的执行不能被其他事务干扰,并发执行的事务之间不能相互干扰 事务的隔离性由锁机制实现
  • 持久性:一个事务一旦被提交,他对数据库中的改变是永久性的。通过redo日志保证。

事务的状态

  • 活动的
  • 部分提交的
  • 失败的
  • 中止的
  • 提交的

使用事务

  • 显示事务
    BEGIN; START TRANSACTION --- COMMIT --- ROLLBACK
  • 隐式事务
    SHOW VARIABLES LIKE 'autocommit' --- SET autocommit =OFF/0/1
    当设置=0时 不论是否开启事务,都需要COMMIT提交,让事务生效,使用ROLLBACK对事务进行回滚;当设置=1,每条SQL语句都会自动进行提交。不过如果采用显示事务开启,只有在COMMOT ROLLBACK才生效。

数据并发问题

  • 脏写:事务A修改了另一个未提交的事务B修改过的数据,发生了脏写。
  • 脏读:事务A读取了被事务B更新但还没有提交的字段,如果事务B进行回滚,相当于事务A读取到了不存在的数据,发生了脏读
  • 不可重读读:事务A前后两次读取的同一字段(由于事务B的更新)但是不同的值。
  • 幻读: 事务A读取到新插入(由于事务B的更新)的数据。发生了幻读,我们把新插入的记录称之为幻影记录

隔离级别

  • 读未提交:所有事务都可以看到其他未提交事务的读取结果
  • 读已提交:事务只能看到提交的事务所做的改变
  • 可重复读:重复读取的数据不会发生改变
  • 可串行化:确保事务在一个表中读取相同的行,禁止其他事务对该表的插入更新删除操作。
    隔离级别越高,数据的一致性越好,但是并发性能越差,mysql默认的隔离级别为可重复读。 SET [GLOBAL|SESSION]TRANSACTION ISOLATION LEVEL

redo 日志

存储引擎是以页为单位来管理存储空间的。在真正访问页面之前,需要把磁盘上的页缓存到内存的Buffer Poll之后可以访问。所有的变更都需要先更新缓冲池中的数据,然后缓冲池中的脏页以一定的频率被刷入到磁盘中(checkPoint机制),通过缓冲池来优化CPU和磁盘之间的鸿沟。
一方面缓冲池消除CPU和磁盘之间的鸿沟,checkpoint机制可以保证数据的最终落盘,然而checkpoint不是每次变更时候就触发,意思master线程隔一段时间处理,可能事务提交刚写到缓冲池,数据库宕机,那么数据丢失无法恢复。redo日志是存储引擎生成的日志,是物理日志,记录的数据页物理变化。保证事务的持久性。事务采用了WAL技术,这种技术的思想就是先写日志,再写磁盘,只有日志(redo log)写入成功才算事务提交成功。当发生宕机且数据未刷到磁盘的时候可以通过redo log来恢复。

特点

  • redo日志降低了刷盘频率
  • redo占用的空间非常小
  • 顺序写入磁盘
  • 事务执行过程中 redo 日志不断记录

构成

  • redo log buffer 保存在内存中,易丢失 默认16M :在服务器启动时候就向操作系统申请了一大片称之为redo log buffer的连续内存空间,这片内存空间被划分成若干个连续的redo log block(512字节)
  • redo log file 保存在硬盘中,持久的

工作流程

  1. 先将原始数据从磁盘中读入到内存中,修改数据的内存拷贝
  2. 生成一条重做日志并写入 redo log buffer,记录的是数据被修改后的值:一个事务--多条语句--若干mtr--多条redo日志。

redo log block:log block header+log block body+ lock block trailer(512字节)

mysql把底层页面中的一次原子访问的过程称之为mtr ,一个所谓的mtr可以包含一组redo日志,在进行崩溃恢复时这一组redo日志作为一个不可分割的整体。写入过程是顺序的,InnoDB提供了一个称之为buf_free的全局变量记录写入位置,不是每次生成一条就插入,而是每个mtr运行过程中产生的日志先暂时存放到一个地方,当mtr结束的时候,将过程中产生的一组redo日志再全部复制到log buffer中
3. 当事务commit时候,将redo log buffer 中的内容刷新到redo log file中,对redo log file采用追加写的方式:checkpoint

redo log file 默认数据目录var/lib/mysql 下默认有两个名为ib_logfile0, ib_logfile1的文件 ,log buffer 中的日志默认情况下就是刷新到两个磁盘文件中(日志文件组)
write pos是当前记录的位置,一边写一边后移;checkpoint 是当前要擦除的位置,每次刷盘到日志文件组中,write pos 位置就会后移更新,每次mysql加载日志文件组恢复时会清空加载过的redo log 记录 并把checkpoint后移更新

  1. 定期将内存中修改的数据以一定的频率(刷盘策略)刷新到磁盘中:
  • 设置为0,每次事务提交时不进行刷盘操作,master thread每隔1s进行一次重做日志的同步;
  • 设置为1,每次事务提交时进行同步(默认策略);只要事务提交成功,redo log记录就在硬盘中,不会有数据丢失,效率差
  • 设置为2,每次事务提交只把redo log file 内容写入文件系统缓存 page cache ,不进行同步。由操作系统自己决定什么时候同步到磁盘中。

undo 日志

undo日志保证事务的原子性,在事务更新数据的前置操作要先写入一个 undo log。undo log 是逻辑日志,对事物回滚时,只是将数据库逻辑的恢复到原来的样子。记录相反的操作主要用于事务的回滚(记录每个修改操作的逆操作)和一致性非锁定读(记录到某种特定的版本--MVCC,即多版本并发控制)

作用

  • 回滚数据 :每当我们要对一条记录做改动时候,需要记录相反的操作。(INSERT--DELETE)
    undo是逻辑日志,只是将数据库逻辑的恢复到原来的样子,数据结构和页本身在回滚后大不相同
  • MVCC:当用户读取一条行记录时 若该记录被其他事务占用,当前事务可以通过undo读取之前的行版本信息实现非锁定读取

存储结构

  1. 回滚段与undo页: undo页的重用,当开启一个事务需要写undo log时候,先得去undo log segment 中去找到一个空闲的位置,当有空位时候就去申请undo页,在这个申请到undo页中进行undo log的写入。undo页可以被重用,当事务提交时候不会立刻删除undo页,undo log在commit后会被放到一个链表中,然后判断undo页的使用是否小于3/4,小于可以被重用,那么它就不会被回收。
  2. 回滚段与事务:

类型

  • insert undo log:指在insert操作中产生的undo log 因为其事务本身可见,对其他事务不可见,故该事务提交后直接删除,不需要purge操作。
  • update undo log: 记录的是对delete 和upate操作产生的,不能在事务提交时候就进行删除,提交时放入undo log 链表,等待purge线程进行最后的删除。
    purge线程两个主要作用:清理undo页和清除page里面带有Delete—_Bit 标志的数据行 不是真正的删除而是一种Delete Mark操作。真正的删除工作需要后台purge线程去完成。

生成过程

DB_ROW_ID :InnoDB会自动添加row_id 的隐藏列作为主键
DB_TRX_ID :每个事务都会分配一个事务ID,当某条记录发生变更时,将事务的事务ID写入tri_id中
DB_ROLL_PTR:回滚指针,本质就是指向undo log的指针。

posted @ 2022-03-21 22:50  Henry19  阅读(20)  评论(0编辑  收藏  举报