【Mysql】事务

news2024/9/22 17:27:17

文章目录

  • 一.什么是事务
    • 1.1. 事物的属性
    • 1.2. 事务的版本支持
    • 1.3. 事务的提交方式
    • 1.4. 事务常见操作
      • 证明事务的回滚
      • 事务崩溃情况下验证回滚
      • 结论
  • 二.事务隔离级别
    • 2.1. 如何理解隔离性
    • 2.2. 隔离性级别
    • 2.3. 脏读,幻读,不可重复读
    • 2.4. 查看,设置隔离级别
    • 2.5. 隔离性验证
  • 三.一致性(Consistency)

一.什么是事务

如果CURD不加控制,会有什么问题

类似于我们刚学多线程写的抢票逻辑代码,数据库中的数据也是临界资源,也需要考虑并发性带来的问题,

image-20221023220145059

CURD满足什么属性,能解决上述问题

  • 买票过程必须满足原子性, 即:我在买票的时候,你不能买,我买完你才能买
  • 买票不能相互影响
  • 买完票应该永久有效
  • 买前买后都要是确定的状态

什么是事务

1)事务就是由一组DML(数据操控语言,比如insert、update…)语句组成,这些语句在逻辑上存在相关性,这一组DML语句要么全部成功,要么全部失败,是一个整体

2)事务就是需要做的事情,这个事情数据量比较大,处理比较复杂

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

3)事务本质上是为了应用层服务的,而不是伴随着数据库系统天生就有的,


1.1. 事物的属性

一个 MySQL 数据库,不止一个事务在运行,同一时刻,甚至有大量的请求被包装成事务,在向 MySQL 服务器发起事务处理请求,而每条事务至少一条 SQL语句,这样如果大家都访问同样的表数据,在不加保护的情况,就绝对会出现问题甚至,因为事务由多条 SQL 构成,那么,也会存在执行到一半出错或者不想再执行的情况,那么已经执行的怎么办呢?

所以,一个完整的事务,绝对不是简单的 sql 集合,还需要满足如下四个属性:

1)原子性: 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节,事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样,

2)一致性 :在事务开始之前和事务结束以后,数据库的完整性没有被破坏,这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作

  • 比如,A想给B转账,A账户扣钱,B账户加钱,不能A账户不扣钱或者少扣钱,B账户多加钱

3)隔离性: 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致,事务隔离分为不同级别,包括读未提交, 读提交, 可重复读 和 串行化 , 隔离性是为了保证数据的安全提出来的同时为了尽可能的保证效率,提出了隔离性的等级

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


上面四个属性,可以简称为 ACID : 原子性(Atomicity,或称不可分割性),一致性(Consistency),隔离性(Isolation,又称独立性),持久性(Durability)


1.2. 事务的版本支持

在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务, MyISAM 不支持,

image-20221027203243275


1.3. 事务的提交方式

事务常见的提交方式有两种:自动提交,手动提交 事物提交方式是在全局设置的

查看事务的提交方式, show variables like 'autocommit';

image-20221027203432187

自动提交默认被打开,如果相对它进行设置,可以用下面的命令:

set autocommit=0; #关闭自动提交
set autocommit=1; #开启自动提交

image-20221027203548886


1.4. 事务常见操作

  1. 开始一个事务:begin/ start transaction;
  2. 创建一个保存点:savepoint+保存点名字;
  3. 回滚操作:rollback to 保存点名字;,如果直接rollback则是直接回滚到事务的最开始,
  4. 提交事务:commit;
  5. 查看事务的隔离级别:select @@tx_isolation;

image-20221027204040336

默认的隔离级别为可重复读


证明事务的回滚

以下面的测试表为例:

image-20221027204409475

可以回滚到之前的保存点,也可以回滚到最开始, 一个事物一旦被提交commit之后就不能回滚了,begin和commit之间的sql叫事务

mysql> select * from account;#空表
mysql> begin;#启动一个事务
mysql> savepoint save1;#在事务的一开始创建保存点
mysql> insert into account values(1,'张三','100.5');#插入测试数据
mysql> select * from account; #查询表的内容
+----+--------+--------+
| id | name   | blance |
+----+--------+--------+
|  1 | 张三   | 100.50 |
+----+--------+--------+
1 row in set (0.00 sec)

mysql> savepoint save2;#插入一条数据以后,再创建一个保存点
mysql> insert into account values(2,'李四','200.5');#插入测试数据
mysql> rollback to save2;#回滚到save2,可以看到save2之后的数据没了

mysql> select * from account;#查询表的内容
+----+--------+--------+
| id | name   | blance |
+----+--------+--------+
|  1 | 张三   | 100.50 |
+----+--------+--------+
1 row in set (0.00 sec)

mysql> rollback to save1;#回滚到save1
mysql> select * from account;
Empty set (0.00 sec)

#save2在save1之后,不能从save1回滚到save2,也就是说只能往前回滚,不能往后  
mysql> rollback to save2;
ERROR 1305 (42000): SAVEPOINT save2 does not exist

mysql> insert into account values(1,'张三','100.5');
mysql> insert into account values(2,'李四','200.5');

mysql> rollback;#直接回滚到事务的最开始

mysql> select * from account;

事务崩溃情况下验证回滚

在隔离级别设置为读未提交的情况下:

image-20221027205607644


自动提交的作用(不启动事务的时候):自动提交开启,即使客户端异常崩溃,也会自动提交, 自动提交关闭,异常情况下数据会回滚,

  • 自动提交开启的时候 (不启动事务的时候)

我们之前所写的所有单条DML,SQL语句,在mysql中默认就是一个事务 ; 默认就是执行完,会被mysql自动提交.

image-20221027210101881


  • 自动提交关闭的时候: (不启动事务的时候)

image-20221027210705342


**事务会自动更改提交方式,不受MySQL是否启动自动提交影响,**即begin启动事务后与mysql是否自动提交无关

  • 实验1:即使开启了自动提交, 事务未commit,客户端崩溃,MySQL自动会回滚,

image-20221027211633564

自动提交已经开启,可是崩溃后还是回滚了,说明事务并不受自动提交影响


实验2:事务commit,客户端崩溃,MySQL数据不会受影响,已经持久化

image-20221027211959405


结论

从上面的例子,我们能看到事务本身的原子性(回滚),持久性(commit),

1.只要输入begin或者start transaction启动事务, 那么事务便必须要通过commit提交,才会持久化,如果运行期间异常终止,就会回滚到最初的状态, 与是否设置自动提交set autocommit无关

2.事务可以手动回滚,同时,当操作异常,(如果没有commit),那么MySQL会自动回滚,自动回滚的场景一般是客户端出现异常崩溃了,

3.对于 InnoDB 每一条 SQL 语言都默认封装成事务,自动提交,(select有特殊情况,因为 MySQL 有 MVCC )

总结:当进行事务的一方突然断开,未能提交事务,那么MySQL回自动进行回滚,事务的操作会自动取消,但一旦提交后,数据就持久化变为永久状态,本质上单条SQL,也被MySQL包装成一个事务,所以如果突然退出,MySQL也会自动回滚,但前提是将MySQL的自动提交关闭,MySQL会自动回滚未完成的事务,以此来维护MySQL事务的原子性,


事务操作注意事项:

1.如果没有设置保存点,也可以回滚,只能回滚到事务的开始,直接使用 rollback(前提是事务还没有提交),如果一个事务被提交了(commit),则不可以回滚(rollback), 我们可以选择回退到哪个保存点,

2.InnoDB 支持事务, MyISAM 不支持事务,

3.开始事务可以使 start transaction 或者 begin,


二.事务隔离级别

隔离性:能还是不能让你看到某些东西 隔离级别:哪些东西应该看到,哪些不应该看到

2.1. 如何理解隔离性

数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性

1.mysql服务可能会同时被多个进程(或者线程)访问,以事务的方式进行访问

2.一个事务可能由多条sql语句构成,因此一个事务有执行前、执行中、执行后的阶段,执行中出现问题,可以随时回滚,所以单个事务,对用户表现出来的特性,就是原子性,

3.所有的事务都需要有执行过程,那么在执行多个事务的时候,很有可能会互相产生影响,从而收到干扰,导致错误的发生,例如:多个事务同时访问同一张表,甚至同一行数据, 为了保证数据执行过程之中尽量不受干扰,就有了一个重要的特征,隔离性

例子:

你妈妈给你说:你要么别学,要学就学到最好,至于你怎么学,中间有什么困难,你妈妈不关心,那么你的学习,对你妈妈来讲,就是原子的,那么你学习过程中,很容易受别人干扰,此时,就需要将你的学习隔离开,保证你的学习环境是健康的


2.2. 隔离性级别

允许事务收到不同程度的干扰,就有了一个重要特征,隔离性级别,

读未提交(read uncommitted)

所有的事务,都可以看到其它事务没有提交的执行结果,相当于没有任何隔离性

  • 带来的后果就是脏读(读取未提交的数据)、幻读(前后多次读取,数据总量不一致)、不可重复读等问题(前后多次读取,数据内容不一致),

读提交(read committed):

一个事务只能看到其它已经提交的事务,这种隔离级别解决了脏读,但是幻读和不可重复读没解决,

可重复读(repeatable read)

这个是MySQL默认隔离级别,确保一个事务在执行中,多次读取数据时,会看到同样的数据

  • 比如,事务A提交,事务B在执行中,不能看到A提交的内容,即事务B在任意时刻,select看到的内容都是一样的,不会受事务A提交的内容影响

串行化(serializable)

这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决了幻读的问题,它在每个读的数据行上面加上共享锁,但是可能会导致超时和锁竞争(这种隔离级别太极端,实际生产基本不使用)


总结:

名称解释
读未提交(Read Uncommitted)所有事务都可以读到其他事务未提交的结果,相当于没有隔离
读提交(Read Committed)一个事务只能读到其他事务提交后的结果,可能会造成不可重复读
可重复读(Repeatable Read)确保一个事务多次读取只会看到同样的数据,可能会造成幻读
串行化(Serializable)通过强制事务排序,使之不可能发生冲突,但可能会导致超时和锁竞争

大多数数据库的隔离级别都是读提交,MySQL默认的隔离级别是可重复读,从上到下,隔离逐渐增强,实际生产不会使用读未提交和串行化,都太极端


为什么存在这么多种类的隔离级别?

隔离性:mysql的内部机制,让"同时"启动, 并发执行的各个事务,看到不同的数据修改(增删改),就叫做隔离性,我们作为一个事务,可以看到不同可见性的数据,程度的不同,叫做隔离级别

为什么存在隔离级别

为了安全! 但是如果只是为了安全,不需要种类繁多的隔离级别,无脑使用串行化不就好了吗,不就是最安全的吗!所以隔离级别不仅仅是为了考虑安全问题,而是在安全+效率之间找平衡点,这个不说mysql决定的,mysql不是这个平衡点的决策者,而是执行者, 所以才会存在种类繁多的隔离级别,相当于我把各种情况列出来,由用户说了算


2.3. 脏读,幻读,不可重复读

脏读

A事务读取B事务尚未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据

  • 脏读最大的问题就是可能会读到不存在的数据,从宏观来看,就是事务A读出了一条不存在的数据

幻读

事务前后多次读取,数据总量不一致

  • 例如:A事务读取表中的数据,如果此时B事务往表中插入或删除数据并提交,A再次读,就和之前读到的数据总量不一样 幻读指的是插入而谈的

幻读的重点在删除和插入,在同一事务中,同样的条件,第一次读取的记录数第二次读取的记录数不一致(因为中间有其他事务提交了插入和删除操作)

不可重复读

事务前后多次读取,数据内容不一致

  • 例如:A事务读取表中的数据,如果此时B事务修改了表中的数据并提交,A再次读就和之前读到的数据内容不一样

不可重复读的重点在修改,在同一事务中,同样的条件,第一次读取的数据和第二次读取的数据不一样(因为中间有其他事务提交了修改), 可重复读指的是插入和删除/修改谈的


2.4. 查看,设置隔离级别

注意:修改全局隔离级别以后,其他客户端要重启才能生效,

隔离级别的分类:读未提交(read uncommitted), 读提交(read committed):可重复读(repeatable read),串行化(serializable)

查看全局隔离级别:

select @@global.tx_isolation;

查看当前会话隔离级别

select @@session.tx_isolation; #简写为:select @@tx_isolation;

设置全局隔离级别,(其它的会话也会被影响):

set global transaction isolation level 隔离级别名称;

设置当前会话隔离级别,只会影响当前会话

set session transaction isolation level 隔离级别名称;

image-20221028161749028


2.5. 隔离性验证

隔离级别脏读不可重复读幻读加锁读
读未提交(read uncommitted)未解决未解决未解决不加锁
读提交(read committed)解决未解决未解决不加锁
可重复读(repeatable read)解决解决MySQL内部解决不加锁
串行化(serializable)解决解决解决加锁

1.当然,所有的隔离机制都是针对并发执行的多个事务,而不是所在的客户进程,隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要我们寻求一个平衡点

2.所谓隔离性,就是一种MySQL内部的机制,让并发执行的多个事务,看到和修改不同的数据,就叫做隔离性,而哪些数据可以看到可以修改,其程度的不同,就由隔离级别决定,

3.事务具有隔离性是为了安全,种类繁多的隔离机制是为了兼顾效率,


验证读未提交 (read uncommitted)

image-20221028144332411

读未提交,相当于没有锁,会产生很多问题,比如脏读,读到另一个执行中事务的未提交数据就叫脏读,实际生产环境是不会使用的


验证读提交(read committed)

image-20221028144947132

读提交会导致其他进程一个事务内同样的两次读取,读到的数据不一样,这个现象就是不可重复读**,不可重复读是有问题的,问题在于不应该让与当前事务并行的事务也读到,造成一个事务读取前后不一致**会影响自身上层业务逻辑

例子:根据存钱的不同把用户筛选出来,发不同的奖品,如果是读提交则可能一个人有多份奖品,多次查询都能查询到他

image-20221028161834370


验证可重复读(repeatable read)

可重复读,MySQL的默认隔离级别,就算修改一方事务已经提交,其他同时存在的事务也无法看到修改的数据,也就是屏蔽与自身并发的事务所做出的修改,

image-20221028154043942

一般数据库只能屏蔽修改和删除操作,无法屏蔽插入操作的

  • 因为隔离性实现是对数据加锁完成的,而insert新增数据是不存在的,也就无法预先加锁,那么一般加锁无法屏蔽这类问题,这也就导致了幻读(多次读取读到新增数据)

但是MySQL在可重复读情况的隔离级别下,解决了幻读问题的


验证串行化:(serializable)

对所有操作加锁进行串行化,不会存在任何问题,但是效率很低,几乎完全不被使用,

当然读取操作select是不会被阻塞的,因为它不会修改数据,如果并发事务一方进行读取写入等操作,另一方事务就会被阻塞住,会被定时解锁

image-20221028155103133


三.一致性(Consistency)

1.事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态,当数据库只包含事务成功提交的结果时,数据库处于一致性状态

2.如果系统运行发生中断,某个事务尚未完成而被迫中断,而该未完成的事务对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确(不一致)的状态,因此一致性是通过原子性来保证的,

3.一致性和用户的业务逻辑强相关,一般MySQL提供技术支持,但是一致性还是要用户业务逻辑做支撑,也就是,一致性,是由用户决定的 ,一致性由上层业务和底层MySQL共同决定,

  • 比如,A想给B转账,A账户扣钱,B账户加钱;业务逻辑不能设置为A账户不扣钱或者少扣钱,B账户加钱

4.一致性不是MySQL中真实存在的一种具体状态,是由原子性、持久性、隔离性共同保证数据库处于一致性的状态

  • 一致性不是一种具体的方案, 而是事务维护的最终目标

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

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

相关文章

T046基于51单片机无线蓝牙控制8位LED灯亮灭proteus仿真原理图PCB

功能: 0.本项目采用STC89C52作为单片机系统的控制MCU 1.通过蓝牙发送指令控制LED灯 2.通过手机APP可以控制8路LED灯的亮灭,可以全亮全灭。 3.通过手机APP可以控制8路LED灯的亮度。每个灯的亮度有3档。具体控制指令如下 a)发送Ox,开启指定LED灯…

日常学习之:Yaml 和 Json 有什么区别

安装 json 是 python 内置 yaml 需要安装 pip install pyyaml格式 对于同样一段数据: test_data {"金山中学":{"101班":{"王宁": {"语文":33,"数学":22,"英语":18}}}}我们用下面的代码分别存入 ya…

ALE的基本介绍、使用与配置

本文将介绍ale插件的基本使用与配置,将从linter的介绍到具体插件的使用与bug的修复~ 本文仅仅时抛砖引玉,更多的使用技巧与功能可以查看项目介绍 ALE的基本介绍、使用与配置ale的介绍ale的基本配置与使用查看你可用的linter安装iverilog——for windowal…

Redisson之lock()和tryLock()的区别

Redisson之lock()和tryLock()的区别和原理解析 在Redisson中 lock() 方法 与 tryLock() 方法是有区别的! 我们先来阐述两者的区别,再分析它们的源码。 lock() 与 tryLock() 的区别 (1)返回值: lock() 是没有返回值…

Vue中的diff算法深度解析

模板tamplate经过parse,optimize,generate等一些列操作之后,把AST转为render function code进而生成虚拟VNode,模板编译阶段基本已经完成了,那么这一章,我们来探讨一下Vue中的一个算法策略–dom diff 首先来介绍下什么…

Java8 遍历List 使用stream().parallel()并发安全

1. parallelStream是什么: java 8引入了并行流的概念来进行并行处理,而并行流(Parallel Stream)利用所有可用CPU内核的优势,并行处理任务。其原理(Parallel Stream)是可以把大任务分成多个小任务执行, 最后再把执行结果进行合并, ForkJoinPoo…

数仓DWS层之旁路缓存优化

优化原因: 外部数据源的查询常常是流式计算的性能瓶颈。以本程序为例,每次查询都要连接 Hbase,数据传输需要做序列化、反序列化,还有网络传输,严重影响时效性。可以通过旁路缓存对查询进行优化。 旁路缓存模式是一种非…

利用Python海龟绘图画一个世界杯的足球

利用Python海龟绘图画一个世界杯的足球 花有重开日 人无再少年 四年一次的世界杯快要结束,为了纪念此次世界杯,特意用Python画了一个足球。 1.设计思路以及实现效果 世界杯足球实现思路: 首先使用海龟画一个圆形作为足球的外边框。然后在足…

3天带你走向实战!阿里顶配版Spring全家桶面试进阶笔记有多强?

Spring框架自从诞生以来就一直备受开发者青睐,它涵盖了Spring、Springboot、SpringCloud等诸多解决方案,一般我们都会统称为Spring全家桶!出于Spring框架在Java开发者心中中的统治地位,所以不管是面试还是工作,Spring都…

夜神模拟器+fiddler抓包(抓取APPhttps请求,删除sll证书校验)

1.安装fiddler https://telerik-fiddler.s3.amazonaws.com/fiddler/FiddlerSetup.exe (下载不了直接去官网找) 2.配置 开启https请求抓取,不抓https可忽略2.修改或查看端口(使用默认8888端口,要自定义端口可修改&#…

Arduino 定时器中断

Arduino 定时器中断 Circuits Arduino 查看原文 简介:Arduino 定时器中断 奥雷里(地球、月亮和太阳) 立式兰花播种机 胶合板书柜扬声器 计时器中断允许您以非常特定的时间间隔执行任务,而不管代码中发生了什么其他事情。我…

Unity ILRuntime Debugger使用及常见问题

目录前言1.安装2.使用3.常见问题前言 ILRuntime支持在VS中断点调试,下面说一下ILRuntime Debugger的使用及常见问题。 1.安装 需要下载对应版本的ILRuntime Debugger VS插件。我是在Unity中PackageManager安装的ILRuntime,可以在插件信息中查看版本。…

记SQL插入emoji成功,但是程序插入失败问题

在执行单测时,碰到了以下熟悉的问题 org.springframework.jdbc.UncategorizedSQLException: ### Error updating database. Cause: java.sql.SQLException: Incorrect string value: \xF0\x9F\x92\x8B for column name at row 1 ### The error may involve com.*…

Java入门教程(16)——条件判断语句

文章目录1. if结构1.1 if 单分支结构1.2 if-else 双分支结构1.3 if-else if-else 多分支结构switch 语句switch 多分支结构1. if结构 1.1 if 单分支结构 语法结构: if(布尔表达式){ 语句块 }实例:掷色子游戏 这里给大家扩展一个Math函数 Math.Random()&#xff0c…

动态规划算法

1.简介 1.动态规划(Dynamic Programming)算法的核心思想是: 将大问题划分为小问题进行解决,从而一步步获取最优解的处理算法; 2.动态规划算法与分治算法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解; 3.与分治法不同…

项目统一规范包管理器

一般来说每个团队都会统一规定项目内只使用一个包管理器,譬如:npm、yarn、pnpm等,我们可以在文档中或者项目根目录REDEM.md中进行描述来形成共识,但毕竟是文档,并不能真正的进行约束,如果有项目成员没有看文…

SpringBoot自动装配原理分析,看完你也能手写一个starter组件

什么是 SpringBoot 2012 年 10 月,一个叫 Mike Youngstrom 的人在 Spring Jira 中创建了一个功能请求,要求在 Spring Framework 中支持无容器 Web 应用程序体系结构,提出了在主容器引导 Spring 容器内配置 Web 容器服务。这件事情对 SpringBo…

Linux 进程间通信

目录 进程间通信的必要性 进程间通信的技术背景 进程间通信的本质理解: 管道IPC:匿名管道 示意图 匿名管道的本质原理: demo示例代码: pipe 系统调用 注意: 管道读写的4种情况: 管道的特点&…

H5UI库和二维码

一、H5UI库 1、使用方法: ​ (1)页面中引入css文件 ​ h5ui.css (h5ui.min.css) ​ (2)页面中引入js文件 ​ jquery.min.js ​ h5ui.min.js 2、组件的用法 ​ (1&#xff09…

为您的高速SPI添加强大和可靠的隔离交流

介绍 串行外设接口(SPI)是工业设备中常用于数字处理器核心和外围设备之间通信的一种协议。然而,为了安全使用,有必要对外围设备和核心进行电隔离。虽然隔离和SPI都是成熟的技术,但将两者接口并不像预期的那么简单。 …