您的位置:首页 > 游戏 > 游戏 > 网站模板制作_html源码网站下载之家_b站视频推广网站动漫_东莞网站建设优化推广

网站模板制作_html源码网站下载之家_b站视频推广网站动漫_东莞网站建设优化推广

2025/1/5 6:25:03 来源:https://blog.csdn.net/2301_77713282/article/details/144691684  浏览:    关键词:网站模板制作_html源码网站下载之家_b站视频推广网站动漫_东莞网站建设优化推广
网站模板制作_html源码网站下载之家_b站视频推广网站动漫_东莞网站建设优化推广

为什么需要事务?

场景:

小明要给小红转账200元。

将这句话分解一下:

  1. 小明的余额 -200;

  2. 小红的余额 +200。

也就是说需要对数据库进行两次操作。这两次操作如果有一条语句执行出现问题,该怎么处理。小明的余额不可能莫名其妙的 -200,小红的余额也不可能莫名其妙的 +200。这两次操作必须是一个完整的整体,要么都执行,要么都不执行。

由此引出事务。

事务概述

数据库事务(transaction)是访问并可能操作各种数据项的一个数据库操作 序列,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。即事务是任意个数据库操作组成的不可分割的操作序列。

在MySQL中只有使用了InnoDB数据库引擎的数据库或表才支持事务。事务处理可以用来维护数据库的完整性,保证成批的SQL语句要么全部执行,要么全部不执行。事务用来管理 insert、update、delete语句。

数据库事务是数据库对执行操作的一种管理机制。

事务特征

事务必须满足4个条件(ACID):原子性(Atomicity,又称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称持久性)、持久性(Durability)。

  1. 原子性(Atomicity)

    原子性是指事务是一个不可分割的工作单位, 事务中的操作要么都发生, 要么都不发生,不会结束再中间某个环节。事务在执行过程中发生错误,会被回滚到(Rollback)到四五开始前的状态,就像这个事务从来没有执行过一样。

  2. 一致性(Consistency)

    当一个事务开始执行之前,数据库的状态是合法的,事务执行后,数据库的状态依然是合法的。一致性确保数据库在事务执行过程中不会破坏数据的完整性和业务规则。

  3. 隔离性(Isolation)

    多个用户并发访问数据库时, 数据库为每一个用户开启的事务, 不能被其他事务的操作数据所干扰, 多个并发事物之间要相互隔离。

  4. 持久性(Durability)

    持久性是指一个事务一旦被提交,他对数据库中的数据的改变是永久性的,即使数据库发生故障也不应该对其有任何影响。

事务使用案例

准备工作

 -- 1 创建一张测试表CREATE TABLE t(id INT,`name` VARCHAR(32));

开启事务

 -- 2.1 开始事务START TRANSACTION;​-- 2.2 开始事务BEGIN;

执行2.1或2.2开启一个事务

添加记录并设置保存点

-- 3.1 设置保存点a
SAVEPOINT a;-- 3.2 执行 dml 操作添加记录
INSERT INTO t VALUE (20, '张三');-- 3.3 设置保存点b
SAVEPOINT b;-- 3.4 再次添加记录
INSERT INTO t VALUE (30, '李四');

执行3.1设置初始保存点,然后执行3.2添加一条数据。添加后可在当前事务中查询到这条数据。其他事物查询不到。

然后执行3.3和3.4两条语句,执行后在当前事务中查询表中数据

事务回滚

-- 4.1 回滚a
ROLLBACK TO a;-- 4.2 回滚b
ROLLBACK TO b;-- 4.3 全部回滚, 回退到事务开始的状态
ROLLBACK;

回滚,可以回滚到设置的某一个保存点,也可以不指定保存点,回到最开始的状态。

执行语句4.2后,将事务回滚到保存点b,查询表中数据

也可以执行回滚到通过语句4.1回滚到保存点a,或语句4.3回滚到事务开始前状态。

此处需要注意的是如果直接执行语句4.1回滚到保存点a,位于保存点a之后创建的保存点将被删除,即保存点b会被删除。

提交事务

-- 5 提交(结束)事务, 提交后不能回滚, 同时删除已设置的保存点
COMMIT;

执行语句5,事务提交,不可回滚,删除所有保存点,数据真正保存下来,其他事务可以查询。

事务设置

默认情况下,MySQL启用自动提交模式。也就是说只要执行 DML(Data Manipulation Language,数据操作语言) 语句,MySQL会立即隐式的提交事务。

关闭自动提交事务:

修改变量 autocommit。autocommit 分为会话系统变量和全局系统变量,所以查询的时候,最好区别是会话系统变量还是全局系统变量。

-- 禁止自动提交
SET GLOBAL autocommit=0;
SET SESSION autocommit=0;-- 开启自动提交
SET GLOBAL autocommit=1;
SET SESSION autocommit=1;-- 查看autocommit模式
SHOW GLOBAL VARIABLES LIKE 'autocommit';
SHOW SESSION VARIABLES LIKE 'autocommit';

事务隔离级别

为什么要有隔离级别?

MySQL是一个服务器/客户端架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就可以称之为一 个会话。我们可以同时在不同的会话里输入各种语句,这些语句可以作为事务的一部分进行处理。不同的会话可以同时发送请求,也就是说服务器可能同时在处理多个事务,这样子就会导致不同的事务可能同时访问到相同的记录。前边提到事务有一个特征称之为隔离性,理论上在某个事务对某个数据进行访问时,其他事务应该进行排队,当该事务提交之后,其他事务才可以继续访问这个数据。但是这样子的话对性能影响太大,所以提出了各种隔离级别,来最大限度的提升系统并发处理事务的能力。只有InnoDB支持事务,所以这里说的事务隔离级别是指数据库引擎 InnoDB 下的事务隔离级别。

并发操作存在问题

如果不对并发的情况加以安全措施,可能会出现以下3种问题:

  1. 脏读(dirty read):当一个事务"读取"另一个事务尚未提交的修改(update,insert,delete)时,产生脏读。

  2. 不可重复读(nonrepeatable read):同一查询在同一事务中多次发生,由于其他提交事务所做的"修改"或"删除",每次返回不同的结果集,此时发生不可重复读。

  3. 幻读(phantom read):同一查询在同一事务中多次进行,由于其他提交事务所做的"插入"操作,每次返回不同的结果集,此时发生幻读。

四种隔离级别

查看隔离级别

SELECT @@session.transaction_isolation,@@transaction_isolation;

MySQL提供四种不同级别的隔离级别,实际开发中可以根据不同的需要场景,选择不同的隔离级别,除了串行级别以外其他级别都会存在某种问题。

准备工作

表结构

读未提交(read uncommitted)

-- 设置会话隔离级别为读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

一个事务可以读到另一个事务还未提交的数据。

问题:脏读,不可重复读,幻读

按照如图所示序号执行,左侧事务未提交的数据在右侧可以直接查询到,即脏读。

读已提交(read committed)

-- 设置会话隔离级别为读已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

一个事务只能读到另一个事务已提交的数据。但是可能因为别的事务对数据删、改操作,导致当前事务多次执行同一查询语句查询结果不一致,即不可重复读。

问题:不可重复读,幻读

修改为读已提交后,上述的读未提交的操作流程会发现,右侧事务无法读取到左侧事务未提交的数据。如图所示:

左侧事务提交后,右侧事务可以查询到李四的数据。

不可重复读演示:

初始数据:

执行流程:

执行6时,可查询到表数据:

执行8时,可查询到表数据:

对于左侧事务只是将修改操作实行完成后就进行了提交,右侧事务进行了两次相同的查询操作,第一次查询到的是李四,可是在左侧事务修改提交后,查询到的却是王五,即不可重复读,如果左侧事务执行的是删除,右侧事务也会出现相同的情况。

可重复读(repeatable read,MySQL默认隔离级别)

-- 设置会话隔离级别为可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

解决了不可重复读问题,但是可能因为别的事务对数添加记录操作,导致当前事务多次执行同一查询语句查询结果不一致,即幻读。

问题:幻读

幻读演示:

初始表数据

执行流程:

执行6时,可查询到表数据:

执行8时,可查询到表数据:

对于左侧事务只是添加了一条数据并提交事务,对于右侧事务就会出现同一事务不同结果数的情况,称之为幻读。

串行化(serializable)

-- 设置会话隔离级别为串行化
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

一次只允许一个事务操作,相当于加锁,即使一个事务在读取操作,另一个事务也不可添加数据。

执行流程:

事务实现原理

MySQL的日志有很多种,如二进制日志、错误日志、查询日志、慢查询日 志等,此外InnoDB存储引擎还提供了两种事务日志:Redo Log (重做日志)Undo Log(回滚日志)。其中Redo Log用于保证事务持久性;Undo Log则是事务原子性隔离性实现的基础。

持久性实现

Redo Log 用来记录已提交事务的变更信息的日志。Redo Log 存储的是物理操作日志,即对数据库物理页的修改操作。它记录了每个事务对数据库的所有修改(包括插入、更新、删除等操作)。在事务提交后,MySQL 会将相关的修改写入到 Redo Log,并在磁盘上持久化。即使数据库崩溃,系统可以根据 Redo Log 恢复已提交事务的操作,确保数据不丢失。

原子性实现

实现原子性的关键,是当事务回滚时能够撤销所有已经成功执行的sql语 句。InnoDB实现回滚,使用到Undo log日志文件,当我们执行一个insert语句时,在Undo log日志文件中记录一个delete语句;执行delete语句时,在日志文件中记录insert语句;执行update时,记录一个变回原数据的update操作。即每次执行时,记录一个他的反向操作。当事务回滚时,执行Undo log中的反向语句。

隔离性实现(MVCC)

MVCC(多版本并发控制,Multi-Version Concurrent Control),是 MySQL 提高性能的一种方式,配合 Undo Log 和版本链,让不同事务的 读-写、写-读 操作可以实现并发,从而提升系统性能。

MVCC 使得数据库在进行 读 操作时不会对数据加锁,普通的 SELECT 请求不会加锁,提高了数据库的并发处理能力。借助MVCC,数据库可以实现 READ COMMITED,REPEATABLE READ 等隔离级别。

InnoDB 的 MVCC 是通过在每行记录后保存两个隐藏的列来实现。一个保存行的事务 ID(db_trx_id),一个保存了行的回滚指针(db_roll_ptr)。

db_trx_id:每次对某记录进行改动时,都会把对应的事务 ID 赋值给 trx_id 隐藏列。

db_roll_ptr:每次对记录进行改动时,都会把旧版本写入到 Undo Log 日志中,然后这个隐藏列相当于一个指针,可以通过它来找到该记录修改前的信息。

对于表结构如图所示的表,通过命令提示符切换到存储该表数据的路径下,通过idb2sdi 表名.ibd查看表底层结构。

可以看到确实有如下两个隐藏的列。

对该记录每次更新后,都会将旧值放到一条 Undo Log 中,当做是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被 db_roll_ptr 属性连接成一个链表,把这个链表称为版本链,版本链的头结点就是当前记录最新的值,每个版本中包含生成该版本时对应的事务 ID,这个信息很重要。

readView(读视图)是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交事务)id。

当隔离级别为读已提交时,在一个事务中,每次读取时,都会从历史版本记录中,获取一个最新的快照。这样,每次读到的都是最新的数据。这样就会导致出现不可重复读问题。

当隔离级别为可重复度时,在第一次读时会获取一个快照,之后再次读取时,还是从第一次生成的快照中读取数据。

一致性实现

以上三个都满足,即可实现一致性。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com