Bootstrap

【mysql】—— 事务

目录

(一)前言

(二)事务的理解 

1、为什么会出现事务

2、什么是事务?

3、事务的版本支持

4、事务提交方式  

(三)事务常见操作方式

1、正常演示 - 证明事务的开始与回滚

2、非正常演示

(四)事务隔离级别

  1、查看与设置隔离性

2、读未提交

3、读提交 

4、可重复读 

5、串行化

(五)总结与回顾


(一)前言

首先,我先通过以下场景来引出本期将要学习的内容!!!

上述火车票售票系统可能会出现这样的状况:

  • 当客户端A检测到还有一张票时,将票卖掉,还没有执行更新数据库时,此时客户端B检查了票数,发现大于0,于是又卖了一次票。然后A将票数更新回数据库。库。这是就出现了同一张票被卖了两次。

此时我们就会想CURD 满足什么属性,能解决上述问题?
  • 1. 买票的过程得是原子的吧
  • 2. 买票互相应该不能影响吧
  • 3. 买完票应该要永久有效吧
  • 4. 买前,和买后都要是确定的状态吧

(二)事务的理解 

1、为什么会出现事务

事务被 MySQL 编写者设计出来 , 本质是为了当应用程序访问数据库的时候 , 事务能够简化我们的编程模型 , 不需要我们去考虑各种各样的潜在错误和并发问题. 可以想一下当我们使用事务时 , 要么提交 , 要么回滚 , 我们不会去考虑网络异常了, 服务器宕机了 , 同时更改一个数据怎么办对吧 ?
  • 因此事务本质上是为了应用层服务的,而不是伴随着数据库系统天生就有的.

总的来说,事务的出现是为了应对复杂的业务需求和数据库操作的多样性,确保数据的正确性和可靠性。通过提供事务支持,数据库管理系统可以保证在各种情况下都能维护数据的一致性和完整性。 


2、什么是事务?

MySQL事务是由一系列SQL语句组成的逻辑操作单元,这些操作要么全部成功执行,要么全部失败回滚。

事务就是要做的或所做的事情,主要用于处理操作量大,复杂度高的数据。假设一种场景:
  • 你毕业了,学校的教务系统后台 MySQL 中,不在需要你的数据,要删除你的所有信息(一般不会) ), 那么要删除你的基本信息(姓名,电话,籍贯等)的同时,也删除和你有关的其他信息;
  • 比如:你的各科成绩,你在校表现,甚至你在论坛发过的文章等。这样,就需要多条 MySQL 语句构成,那么所有这些操作合起来,就构成了一个事务。

正如我们上面所说,一个 MySQL 数据库,可不止你一个事务在运行,同一时刻,甚至有大量的请求被包装成事务,在向 MySQL 服务器发起事务处理请求。而每条事务至少一条 SQL ,最多很多 SQL , 这样如果大家都访问同样的表数据,在不加保护的情况,就绝对会出现问题。甚至,因为事务由多条 SQL 构成,那么,也会存在执行到一半出错或者不想再执行的情况,那么已经执行的怎么办呢?
所以,一个完整的事务,绝对不是简单的 sql 集合,还需要满足如下四个属性,在MySQL中,事务的概念符合 ACID原子性、一致性、隔离性、持久性):
  1. 原子性(Atomicity):事务是一个原子操作单元,要么全部提交成功,要么全部失败回滚,不存在部分提交的情况,就像这个事务从来没有执行过一样。

  2. 一致性(Consistency):事务在执行前后,数据库都必须保持一致状态。即使事务执行失败,数据库也不能处于不一致状态。

  3. 隔离性(Isolation):事务之间是相互隔离的,一个事务的执行不应该被其他事务所干扰。事务隔离性的级别有不同的隔离级别(如读未提交、读提交、可重复读、串行化),可以根据需求进行设置。

  4. 持久性: 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

3、事务的版本支持

MySQL 中只有使用了 Innodb(开始配置过)  数据库引擎的数据库或表才支持事务, MyISAM 不支持。
  • 查看数据库引擎


4、事务提交方式  

事务的提交方式常见的有两种:
  • 自动提交
  • 手动提交
  • 查看事务提交方式 :

  • 我们也可以用 SET 来改变 MySQL 的自动提交模式:


(三)事务常见操作方式

为了便于演示,我们将mysql的默认隔离级别设置成读未提交,具体操作后面专门会讲,现在已使用为主。
set global transaction isolation level READ UNCOMMITTED;

创建测试表:
create table if not exists account(
    id int primary key,
    name varchar(50) not null default '',
    blance decimal(10,2) not null default 0.0
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;
  •  查询展示:


1、正常演示 - 证明事务的开始与回滚

  • 1.案例一:

  •  2.案例二:

  •  3.案例三: 


2、非正常演示

案例一:证明未commit,客户端崩溃,MySQL自动会回滚(隔离级别设置为读未提交)


案例二 :证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化 


案例三:对比试验。证明begin操作会自动更改提交方式,不会受MySQL是否自动提交影响 

  • 准备工作:

  •  实验现象:


 案例4 : 证明单条 SQL 与事务的关系 

 


【小结】

  1. 只要输入begin或者start transaction,事务便必须要通过commit提交,才会持久化,与是 否设置set autocommit无关。
  2. 事务可以手动回滚,同时,当操作异常,MySQL会自动回滚
  3. 对于 InnoDB 每一条 SQL 语言都默认封装成事务,自动提交。(select有特殊情况,因为 MySQL MVCC
  4. 从上面的例子,我们能看到事务本身的原子性(回滚),持久性(commit)

 

事务操作注意事项
  1. 如果没有设置保存点,也可以回滚,只能回滚到事务的开始。直接使用 rollback(前提是事务 还没有提交);
  2. 如果一个事务被提交了(commit),则不可以回退(rollback);
  3. 可以选择回退到哪个保存点;
  4. InnoDB 支持事务, MyISAM 不支持事务;
  5. 开始事务可以使 start transaction 或者 begin。

(四)事务隔离级别

  1. MySQL服务可能会同时被多个客户端进程(线程)访问,访问的方式以事务方式进行;
  2. 一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶段。而所谓的原子性,其实就是让用户层,要么看到执行前,要么看到执行后。执行中出现问题,可以随时回滚。所以单个事务,对用户表现出来的特性,就是原子性。
  3. 但,毕竟所有事务都要有个执行过程,那么在多个事务各自执行多个SQL的时候,就还是有可能会出现互相影响的情况。比如:多个事务同时访问同一张表,甚至同一行数据。
  4. 数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性
  5. 数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别

 隔离级别 

  • 读未提交【Read Uncommitted: 在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果。(实际生产中不可能使用这种隔离级别的),但是相当于没有任何隔离性,也会有很多 并发问题,如脏读,幻读,不可重复读等,我们上面为了做实验方便,用的就是这个隔离性。
  • 读提交【Read Committed:该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默 认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种离级别会引起不可重复读,即一个事务执行时,如果多次 select, 可能得到不同的结果。
  • 可重复读【Repeatable Read: 这是 MySQL 默认的隔离级别,它确保同一个事务,在执行 中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题。
  • ​​​​​​​串行化【Serializable: 这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突, 从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争 (这种隔离级别太极端,实际生产基本不使用)

 


隔离级别如何实现:
  • 隔离,基本都是通过实现的,不同的隔离级别,锁的使用是不同的。常见有,表锁,行锁,读锁,写锁,间隙锁(GAP),Next-Key(GAP+行锁)等。不过,我们目前现有这个认识就行,先关注上层使用。

  1、查看与设置隔离性

  • 查看隔离性:


  •  设置隔离性:设置当前会话隔离性,另起一个会话,只影响当前会话


  •  设置隔离性:设置全局隔离性,另起一个会话,会被影响

 


2、读未提交

特点:几乎没有加锁,虽然效率高,但是问题太多,严重不建议采用

 

  • 一个事务在执行中,读到另一个执行中事务的更新(或其他操作)但是未commit的数据,这种现象叫做脏读 (dirty read)

3、读提交 

 

  • 左边终端 commit之后,看到了数据发生变化,但是此时还在当前事务中,并未commit;
  • 此时就造成了,同一个事务内,同样的读取,在不同的时间段 (依旧还在事务操作中!),读取到了不同的值,这种现象叫做不可重复读(non reapeatable read)!!

 


4、可重复读 

  • 准备工作:设置全局隔离级别 RR

  • 操作步骤:

  •  可以看到,在右边终端中,事务无论什么时候进行查找,看到的结果都是一致的,这叫做可重复读!

如果将上图左边的终端中的update操作,改成insert操作,会有什么问题?? 

【小结】

  • 大家可以在左边终端commit之后多去查看几次,发现左边终端在对应事务中insert的数据,在右边终端的事务周期中,也没有什么影响,也符合可重复的特点;
  • 但是,一般的数据库在可重复读情况的时候,无法屏蔽其他事务insert的数据(为什么?因为隔离性实现是对数据加锁完成的,而insert待插入的数据因为并不存在,那么一般加锁无法屏蔽这类问题),会造成虽然大部分内容是可重复读的,但是insert的数据在可重复读情况被读取出来,导致多次查找时,会多查找出来新的记录,就如同产生了幻觉。这种现象,叫做幻读(phantom read)。
  • 很明显,MySQLRR级别的时候,是解决了幻读问题的(解决的方式是用Next-Key(GAP锁+行锁)解决的。

5、串行化

 

  • ​​​​​​​对所有操作全部加锁,进行串行化,不会有问题,但是只要串行化,效率很低,几乎完全不会被采用 


【小结】

  1. 其中隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个平衡点。
  2. 不可重复读的重点是修改和删除:同样的条件, 你读取过的数据,再次读取出来发现值不一样了幻读的重点在于新增:同样的条件, 1次和第2次读出来的记录数不一样
  3. 说明: mysql 默认的隔离级别是可重复读,一般情况下不要修改
  4. 上面的例子可以看出,事务也有长短事务这样的概念。事务间互相影响,指的是事务在并行执行的时候,即都没有commit的时候,影响会比较大

 一致性(Consistency)

  1. 事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务成功提交的结果时,数据库处于一致性状态。如果系统运行发生中断,某个事务尚未完成而被迫中断,而改未完成的事务对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确(不一致)的状态。因此一致性是通过原子性来保证的。
  2. 其实一致性和用户的业务逻辑强相关,一般MySQL提供技术支持,但是一致性还是要用户业务逻辑做支撑,也就是,一致性,是由用户决定的。
  3. 而技术上,通过AID保证C

(五)总结与回顾

以上便是本文的全部内容,接下来简单回顾下本文都讲解了哪些知识!!!

  1. 事务的四个基本特性(ACID):

    • 原子性(Atomicity): 事务是一个原子操作单元,要么全部执行成功,要么全部失败回滚,不存在部分执行的情况。
    • 一致性(Consistency): 事务执行前后,数据库从一个一致状态转变到另一个一致状态,保持数据库的完整性。
    • 隔离性(Isolation): 多个事务之间相互隔离,一个事务的执行不应影响其他事务。
    • 持久性(Durability): 一旦事务被提交,它对数据库的改变应该是永久性的,即使在系统故障的情况下也不应该丢失。
  2. 事务的开始和结束:

    • 事务可以通过START TRANSACTIONBEGIN语句开始。
    • 提交事务使用COMMIT语句,回滚事务使用ROLLBACK语句。
  3. 自动提交模式:

    • 默认情况下,MySQL 处于自动提交(Auto Commit)模式,即每个语句都会自动成为一个事务,并立即提交。
    • 可以使用SET autocommit = 0;禁用自动提交,然后通过显式的COMMITROLLBACK来控制事务。
  4. 保存点(Savepoint):

    • MySQL 支持使用SAVEPOINTROLLBACK TO savepoint语句创建和使用保存点,以实现在事务中的部分回滚。
  5. 事务隔离级别:

    • MySQL支持不同的事务隔离级别,包括READ UNCOMMITTEDREAD COMMITTEDREPEATABLE READSERIALIZABLE
    • 隔离级别决定了事务之间的可见性和并发控制的方式。

到此,本文的内容便全部结束了。感谢大家的观看和支持!!! 

;