【无标题】Mysql事务相关内容总结

Mysql 事务概念

事务是访问并更新数据库中各种数据项的一个程序执行单元。可以是一条简单的sql语句,也可以是一组复杂的sql语句组合而成。

Mysql 事务特性

ACID
原子性(Atomicity,或称不可分割性)
一致性(Consistency)
隔离性(Isolation)
持久性(Durability)

原子性(atomicity):语句要么全执行,要么全不执行,是事务最核心的特性,事务本身就是以原子性来定义的;实现主要基于undo log

一致性(consistency):数据库总是从一个一致性的状态转换到另外一个一致性的状态。一旦事务提交了,那么就永远都不会改变了。

隔离性(isolation):一个事务在完全提交之前,对其他事务是不可见的。

持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。实现主要基于redo log 。

Mysql事务隔离级别

并发事务的四种场景

1、读读
两个事务同时读一个数据——只要不发生数据修改,就没有问题。

2、写写
两个事务同时写一个数据——会发生脏写。所以是零容忍的,最低的隔离级别也解决了他。

3、读写/写读
宏观来看,是一回事——一个读一个写。
微观来看,是两回事——先读后写 和 先写后读。

并发事务带来的问题——更新丢失、脏读、不可重复读、幻读

更新丢失(脏写)

多个事务同时修改了同一个内容,那么最终数据库内留下了的就仅仅是最后一个提交的。因此前面所进行的提交就会出现更新丢失。
这个问题是不可容忍的,哪怕最低级的隔离级别都已经解决了他。

脏读

一个事务正在修改但是没有提交,此数据目前处于不一致状态。此刻另一个事务也请求此纪录,则会读取到这些修改但未提交的脏数据,称之为脏读。

不可重复读

同一事务,同样的条件下,前后两次读取到了不一样的数据。(中间有其他事务进行了修改

幻读

同一事务,同样的条件下,前后两次读取到了不一样的记录数。(中间有其他事务进行了新增/删除

4种隔离级别

Read Uncommitted(读未提交)

该隔离级别的事务可以看到其他事务中未提交的数据。

存在脏读的问题

Read Committed(读已提交)

该隔离级别的事务能读取到已经提交事务的数据。

避免了脏读,但存在不可重复读。

Repeatable Read(可重读)(默认级别

当前事务读不到其它事务修改并提交的数据,从而不会出现不可重复读问题。
MySQL 默认的事务隔离级别。

解决了不可重复读和大部分情况下的幻读,但没有完全解决幻读。

Serializable(序列化)

强制序列化执行,直接放弃了多线程并发。因此全部解决,但效率低下。

【无标题】Mysql事务相关内容总结_第1张图片

解决方案

1、传统方案,采取加锁的方案实现4种隔离级别。
2、Mysql的方案,使用MVCC机制实现。

通过锁实现

MVCC机制

为了解决Mysql并发事务所带来的问题,提供了两种机制:利用锁,和MVCC机制。

简介

MVCC——Multi-Version Concurrency Control,即多版本并发控制技术。运用锁机制会导致部分事务串行化,因此效率会下降。
传统加锁机制中,是出于“防患于未然”考虑,出现脏读、不可重复读、幻读等本身就是小概率事件,为了防止他们,去将所有操纵同一数据的并发读写事务串行化,会影响很多性能。
因此MVCC机制,在线程安全问题和加锁串行化之间做了一定取舍,让两者之间达到了很好的平衡,即防止了脏读、不可重复读及幻读问题的出现,又无需对并发读-写事务加锁处理。

调用时机

MVCC仅有InnoDB引擎支持。
MVCC仅在RC、RR两个机隔离级别中生效——
RU级别下,既然都允许脏读了,那就无所谓隔离 直接用最新的即可。
Serializable级别下,强制串行化,不存在多线程并发,因此无需使用。

实现原理

四个隐藏字段

1、隐藏主键——ROW_ID(6Bytes)
构建聚簇索引时,是根据主键来构建的。若没有设置主键,则生成一个隐藏主键,用于构建。只是这个主键无法在上层使用。

2、删除标识 - Deleted_Bit(1Bytes)
delete一个内容时候,若直接删除,则会需要树结构的重新生成。再恢复又需要重新生成,由此带来的开销极大。因此使用一个标志,标识其已经被删除,再恢复时候修改标识即可。
为了防止“已删除”的数据占用过多的磁盘空间,purger线程会在后台自动清理Deleted_Bit=1/true的行数据。

3、最近更新的事务ID - TRX_ID(6Bytes)
每一个事务都会分配一个事务ID(仅查询的不分配,但对于手动开启的都分配 即使只有select),这个ID单增。

此时事务T1准备修改表字段的值,MySQL会为其分配一个事务ID=1,当事务T2准备向表中插入一条数据时,又会为这个事务分配一个ID=2…
但有一个细节点需要记住:MySQL对于所有包含写入SQL的事务,会为其分配一个顺序递增的事务ID,但如果是一条select查询语句,则分配的事务ID=0。
不过对于手动开启的事务,MySQL都会为其分配事务ID,就算这个手动开启的事务中仅有select操作。
表中的隐藏字段TRX_ID,记录的就是最近一次改动当前这条数据的事务ID,这个字段是实现MVCC机制的核心之一。

4、回滚指针 - ROLL_PTR(7Bytes)
指针存放着undo-log的地址,undo-log中存放的是一个版本链,是一个单向链表。
每次回滚操作时,会根据这个版本链找到对应的版本。
每次更新操作时,会把最新的数据插入到链表头(而不是链表尾)。

undo-log中的内容哦同样会进行移除,移除的工作同样由purger线程负责,purger线程内部也会维护一个ReadView,它会以此作为判断依据,来决定何时移除Undo记录。

ReadView

ReadView就是一个快照,事务读取数据时,会生成一个读快照,即ReadView。保存着这个时刻数据库中的数据信息。ReadView会根据事务的隔离级别决定在某个事务开始时,该事务能看到什么信息。

Mysql日志

分类&&概述

日志 保障性质 主要用途 生成自 描述
undo log 原子性 用于事务回滚和 MVCC 由InnoDB生成 若事务没用完成需要回滚,则根据undo log进行回滚。回滚所进行的是逆操作,例如Insert操作的回滚是DeleteDelete的回滚是Insert
redo log 持久性 用于掉电等故障恢复 由InnoDB生成 InnoDB是先提交事务到缓存(Buffer Pool),再定期从缓存写入磁盘。若断电等情况导致缓存中的事务没有提交,则需要根据redo log来恢复。
bin log 用于数据备份和主从复制 由Server层生成 MySQL 在完成一条更新操作后,Server 层还会生成一条 binlog,等之后事务提交的时候,会将该事物执行过程中产生的所有 binlog 统一写 入 binlog 文件。binlog 文件是记录了所有数据库表结构变更和表数据修改的日志,不会记录查询类的操作,比如 SELECT 和 SHOW 操作。

binlog和redolog的区别

(1)重做日志是在InnoDB存储引擎层产生的,而二进制日志是在MySQL数据库上层产生的,二进制日志不仅仅针对InnoDB存储引擎,任何存储引擎都会产生二进制日志。

(2)两种日志的记录内容形式不同。二进制日志是一种逻辑日志,记录的是SQL语句;而InnoDB存储引擎层面的重做日志是物理格式日志,记录的是对于每个页的修改。

(3)写入磁盘的时间不同,二进制日志只在事务提交完成后进行一次写入,而redo log在事务进行中不断的写入。

本文参考自

MySQL数据库中的事务在面试中的高频考点
小林coding——MySQL 日志:undo log、redo log、binlog 有什么用?

MySQL之MVCC机制:为什么你改了的数据我还看不见?

编程迷思——深入学习MySQL事务:ACID特性的实现原理

你可能感兴趣的:(#,Mysql,基础组件学习,mysql,oracle,数据库)