当前位置: 首页 > news >正文

MySQL深入理解事务(详解)

事务概述

事务是数据库区别于文件系统的重要特性之一,当我们有了事务就会让数据库始终保持一致性,同时我们还能通过事务机制恢复到某个时间点,这样可以保证已提交到数据库的修改不会因为系统崩溃而丢失。

1、基本概念

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

事务处理的机制:保证所有的事务都作为一个工作单元来执行,即使出项了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都提交commit,那么这些修改就永久的保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚rollback到最初状态

#案例:AA用户给BB用户转账100
update account set money = money - 100 where name = 'AA';
update account set money = money + 100 where name = 'BB';

2、事务的ACID特性

  • 原子性(atomicity)

原子性是指事务是一个不可分割的工作单元,要么全部提交,要么全部失败回滚。既要么转账成功,要么转账失败,是不存在中间的状态。如果无法保证原子性会怎么样?就会出项数据不一致的情形,A账户减去100元,而B账户增加100元操作失败,系统将无故丢失100元。

  • 一致性(consistency)

一致性是指事务执行前后,数据从一个合法性状态变换到另外一个合法性状态。这种状态是语义上的而不是语法上的,跟具体的业务有关。

那什么是合法的数据状态呢?满足预定的约束的状态就叫做合法的状态。通俗一点,这状态是由你自己来定义的(比如满足现实世界中的约束)。满足这个状态,数据就是一致性的,不满足这个状态,数据就是不一致的!如果事务中的某个操作失败了,系统就会自动撤销当前正在执行的事务,返回到事务操作之前的状态。

举例1:A账户有200元,转账300元出去,此时A账户余额为-100元。你自然就发现了此时数据是不一致的,为什么呢?因为你定义了一个状态,余额这列必须>=0。

举例2:A账户有200元,转账50元给B账户,A账户的钱扣了,但是B账户因为各种意外,余额并没有增加。你也知道此时数据是不一致的,为什么呢?因为你定义了一个状态,要求A+B的总余额 必须不变。

  • 隔离性(isolation)

事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

如果无法保证隔离性会怎么样?假设A账户有200元,B账户0元,A账户往B账户转账两次,每次金额为50元,分别在两个事务中执行。如果无法保证隔离性,会出项下面的情形:

UPDATE accounts SET money = money - 50 where NAME = 'AA';UPDATE accounts SET money = money + 50 where NAME = 'BB';
事务1事务2
从磁盘上将A账户余额读取到变量A中 A为200
执行操作A=A-50
将A的值写回磁盘 A为150
从磁盘中将B账户余额读取到变量B中 B为0
执行操作B=B+50
从磁盘上将A账户余额读取到变量A中 A为150
执行操作A=A-50
将A的值写回磁盘 A为100
从磁盘中将B账户余额读取到变量B中 B为0
执行操作B=B+50
将B值写回磁盘 B为50
将B值写回磁盘 B为50
  • 持久性(durability)

持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作的数据库故障不应该对其他有任何影响。

持久性是通过事务日志来保证的。日志包括了重做日志回滚日志。当我们通过事务对数据进行修改的时候,首先会将数据库的变化信息记录到重做日志中,然后再对数据库中对应的行进行修改。这样中的好处是,即使数据库系统崩溃,数据库重启后也能找到没有更新到数据库系统中的重做日志,重新执行,从而使事务具有持久性。

总结:ACID是事务的四大特性,在这四个特性中,原子性是基础,隔离性是手段,一致性是约束条件,而持久性是我们的目的。数据库事务,其实就是数据库设计者为了方便起见,把需要保证的原子性,隔离性,一致性和持久性的一个或多个数据库操作称为一个事务。

3、数据并发问题

针对事务的隔离性和并发性,我们怎么做取舍呢?先看一下访问相同数据的事务在不保证串行执行(也就是执行完一个再执行另一个)的情况下可能会出现哪些问题:

1、脏写(Dirty Write)

对于两个事务SessionA、SessionB,如果事务SessionA修改了另一个未提交事务SessonB修改过的数据,那就意味着发生了脏写,如图所示:

发生时间编号SessionASessionB
1Begin;
2Begin;
3UPDATE student SET name = ‘李四’ WHERE studentno = 1;
4UPDATE student SET name=‘张三’ WHERE studentno = 1;
5COMMIT;
6ROLLBACK;

SessionA和SessionB各开启了一个事务,SessionB中的事务先将studentso列为1的记录的name更新为‘李四’,然后SessionA中的事务接着又把这条studentno列为1的记录的name列更新为‘张三’。如果之后SessionB中的事务进行了回滚,那么SessionA中更新也将不复存在,这种现象就称之为脏写。这时SessionA中的事务就没有效果了,明明把数据更新了,最后也提交事务了,最后看到的数据没有变化。这里大家对事务的隔离级别比较了解的话,会发现默认隔离级别下,上面SessionA中的更新语句会处于等待状态,这里只是跟大家说明一下会出现这样现象。

2、脏读(Dirty Read)

对于两个事务SessionA、SessionB,Session A 读取了已经被Session B更新但还没有被提交的字段。之后若Session B回滚,Session A 读取的内容就是临时且无效的。如图所示:

发生时间编号SessionASessionB
1Begin;
2Begin;
3UPDATE student SET name = ‘张三’ WHERE studentno = 1;
4SELECT * FROM student WHERE studentno = 1;(如果读取到列name的值为’张三’,则意味着发生了脏读)
5COMMIT;
6ROLLBACK;

SessionA和SeesionB各开启了一个事务,SessionB中的事务先将studentno列为1的记录的name列更新为‘张三’,然后SessionA中的事务再去查询这条studentno为1的记录,如果读取到列name的值为’张三‘,而Session B中的事务稍后进行了回滚,那么SessionA中的事务相当于读取到了一个不存在的数据,这种现象就称之为脏读

3、不可重复读(Non-Repeatable Read)

对于两个事务SessionA、SessionB,Session A读取了一个字段,然后SessionB更新了该字段,之后Session A再次读取同一个字段,值就不同了,那就意味着发生了不可重复读。

发生时间编号SessionASessionB
1Begin;
2SELECT * FROM student WHERE studentno = 1;(此时读到的列name的值为’王五‘)
3UPDATE student SET name= ‘张三’ WHERE studentno = 1;
4SELECT * FROM student WHERE studentno = 1;(如果读到列name的值为’张三‘,则意味着发生了不可重复读)
5UPDATE student SET name = ‘李四’ WHERE studentno = 1;
6SELECT * FROM student WHERE studentno = 1;(如果读到列name的值为’李四‘,则意味着发生了不可重复读)

我们在Session B中提交几个隐式事务(注意是隐式事务,意味着语句结束事务就提交了),这些事务都修改了studentno列为1的记录的列name的值,每次事务提交之后,如果Session A中的事务都可以查看到最新的值,这种现象就称之为不可重复读

4、幻读(Phantom)

对于两个事务Session A、Session B,SessionA从一个表中读取了一个字段,然后SessionB在该表中插入 了一些新的行。之后,如果Session A再次读取同一个表,就会出多几行。那就意味着发生了幻读

发生时间编号SessionASessionB
1Begin;
2SELECT * FROM student WHERE studentno>0;(此时读取到的列name的值为’张三‘)
3INSERT INTO student VALUES (2,‘赵六’,‘2班’);
4SELECT * FROM student WHERE studentno>0;(如果读取到了列name的值为’张三‘、’赵六‘的记录,则意味着发生了幻读)

SessionA中的事务先根据条件studentno >0这个条件查询表student,得到了name的值为’张三‘的记录;之后SessionB中提交了一个隐式事务,该事务向表student中插入了一条新的记录;之后SessionA中的事务再根据相同的条件studentno > 0 查询表student,得到的结果集中包含Session B中的事务新插入的那条记录,这种现象也被称之为幻读。我们把新插入的那些记录称之为幻影记录

注意1:

有的同学会产生疑问,那如果SessionB中删除了一些符合studentno > 0的记录而不是插入新记录,那Session A之后再根据studentno > 0的条件读取的记录变少了,这种现象算不算幻读呢?这种现象不属于幻读,幻读强调的是一个事务按照某个相同条件多次读取记录时,后读取时读到了之前没有读到的记录

注意2:

那对于先前已经读到的记录,之后又读取不到这种情况,算啥呢?这相当于对每一条记录都发生了不可重复读的现象。幻读只是重点强调了读取到了之前读取没有获取到的记录。

4、SQL中的四种隔离级别

上面介绍了几种并发事务执行过程中可能遇到的一些问题,这些问题有轻重缓急之分,我们给这些问题按照严重性来排一下序:

脏写 > 脏读 > 不可重复读 > 幻读

我们愿意舍去一部分隔离性来换取一部分性能在这里就体现在:设立一些隔离级别,隔离级别越低,并发问题发生的就越多。SQL标准中设立了4个隔离级别:

  • READ UNCOMMITTED:读未提交,在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。不能避免脏读,不可重复读,幻读。
  • READ COMMITTED:读已提交,它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。可以避免脏读,但不可重复读,幻读问题仍然存在。
  • REPEATABLE READ:可重复读,事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读,不可重复读,但幻读问题仍然存在。这是MySQL的默认隔离级别。
  • SERIALIZABLE:可串行化,确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入,更新和删除操作。所有的并发问题都可以避免,但性能十分底下。能避免脏读、不可重复读和幻读。

SQL标准中规定,针对不同的隔离级别,并发事务可以发生不同严重程度的问题,具体情况如下:

隔离级别脏读可能性不可重复读可能性幻读可能性加锁读
READ UNCOMMITTEDYesYesYesNo
READ COMMITTEDNoYesYesNo
REPEATABLE READNoNoYesNo
SERIALIZABLENoNoNoYes

Yes:表示会出现的可能性,No:表示不会出现的可能性。

脏写没有涉及到?因为脏写这个问题太严重了,不论是哪种隔离级别,都不允许脏写的情况发生。

不同的隔离级别有不同的现象,并有不同的锁和并发机制,隔离级别越高,数据库的并发性能就越差。

相关文章:

MySQL深入理解事务(详解)

事务概述 事务是数据库区别于文件系统的重要特性之一,当我们有了事务就会让数据库始终保持一致性,同时我们还能通过事务机制恢复到某个时间点,这样可以保证已提交到数据库的修改不会因为系统崩溃而丢失。 1、基本概念 事务:一组…...

【Linux系统】进程控制

本篇博客整理了进程控制有关的创建、退出、等待、替换操作方面的知识,最终附有模拟实现命令行解释器shell来综合运用进程控制的知识,旨在帮助读者更好地理解进程与进程之间的交互,以及对开发有一个初步了解。 目录 一、进程创建 1.创建子进…...

Go语言数值类型教程

Go语言提供了丰富的数值类型,包括整数类型、浮点类型和复数类型。每种类型都有其特定的用途和存储范围。下面将详细介绍这些类型,并附带示例代码。 原文链接: Go语言数值类型教程 - 红客网-网络安全与渗透技术 1. 整数类型 原文链接&#xf…...

Linux进程控制——Linux进程等待

前言:接着前面进程终止,话不多说我们进入Linux进程等待的学习,如果你还不了解进程终止建议先了解: Linux进程终止 本篇主要内容: 什么是进程等待 为什么要进行进程等待 如何进程等待 进程等待 1. 进程等待的概念2. 进…...

GPT-4o:融合文本、音频和图像的全方位人机交互体验

引言: GPT-4o(“o”代表“omni”)的问世标志着人机交互领域的一次重要突破。它不仅接受文本、音频和图像的任意组合作为输入,还能生成文本、音频和图像输出的任意组合。这一全新的模型不仅在响应速度上达到了惊人的水平,在文本、音频和图像理解方面也表现出色,给人带来了…...

灵活的静态存储控制器 (FSMC)的介绍(STM32F4)

目录 概述 1 认识FSMC 1.1 应用介绍 1.2 FSMC的主要功能 1.2.1 FSMC用途 1.2.2 FSMC的功能 2 FSMC的框架结构 2.1 AHB 接口 2.1.1 AHB 接口的Fault 2.1.2 支持的存储器和事务 2.2 外部器件地址映射 3 地址映射 3.1 NOR/PSRAM地址映射 3.2 NAND/PC卡地址映射 概述…...

nginx-rtmp

1.已经安装nginx;configure配置模块;make编译无需安装;把objs/nginx复制到已安装的宁目录下 ./configure --prefix/usr/local/nginx --add-module/usr/local/src/fastdfs-nginx-module/src --add-module/usr/local/src/nginx-rtmp-module-mas…...

nginx 代理java 请求报502

情况:nginx代理java 请求 后端返回正常,但是经过nginx 时报502 经过多次对比其他接口发现可能是返回的请求头过大,导致nginx 报错:如下 2024/05/13 02:57:12 [error] 88#88: *3755 upstream sent too big header while reading r…...

面试集中营—Redis面试题

一、Redis的线程模型 Redis是基于非阻塞的IO复用模型,内部使用文件事件处理器(file event handler),这个文件事件处理器是单线程的,所以Redis才叫做单线程的模型,它采用IO多路复用机制同时监听多个socket&a…...

关于使用git拉取gitlab仓库的步骤(解决公钥问题和pytho版本和repo版本不对应的问题)

先获取权限,提交ssh-key 虚拟机连接 GitLab并提交代码_gitlab提交mr-CSDN博客 配置完成上诉步骤之后,执行下列指令进行拉去仓库的内容 sudo apt install repo export PATHpwd/.repo/repo:$PATH python3 "实际路径"/repo init -u ssh://gitxx…...

Django图书馆综合项目-学习(2)

接下来我们来实现一下图书管理系统的一些相关功能 1.在书籍的book_index.html中有一个"查看所有书毂"的超链接按钮,点击进入书籍列表book_list.html页面. 这边我们使用之前创建的命名空间去创建超连接 这里的book 是在根路由创建的namespacelist是在bo…...

vue3+ts 获取input 输入框中的值

从前端input 输入框获取值&#xff0c;通过封装axios 将值传给后端服务 数据格式为json html <el-form> <el-form-item label"域名"><el-input v-model"short_url" style"width: 240px"type"text"placeholder&quo…...

Gin框架返回Protobuf类型:提升性能的利器

在构建高效、高性能的微服务架构时&#xff0c;数据序列化和反序列化的性能至关重要。Protocol Buffers&#xff08;简称Protobuf&#xff09;作为一种轻量级且高效的结构化数据存储格式&#xff0c;已经在众多领域得到广泛应用。Gin框架作为Go语言中流行的Web框架&#xff0c;…...

HTML满屏漂浮爱心

目录 写在前面 满屏爱心 代码分析 系列推荐 写在最后 写在前面 小编给大家准备了满屏漂浮爱心代码&#xff0c;一起来看看吧~ 满屏爱心 文件heart.svg <svg xmlns"http://www.w3.org/2000/svg" width"473.8px" height"408.6px" view…...

爬虫应该选择住宅ip代理还是数据中心代理?

住宅代理 住宅代理是互联网服务提供商 (ISP) 提供的 IP 地址&#xff0c;它们是附加到实际物理位置的真实IP地址。住宅代理允许用户通过目标区域内的真实IP地址连接到互联网。 数据中心代理 数据中心代理是指是使用数据中心拥有并管理IP的代理&#xff0c;IP地址来源于数据中…...

百面算法工程师目录 | 深度学习目标检测、语义分割、分类上百种面试问答技巧

本文给大家带来的百面算法工程师是深度学习面试目录大纲&#xff0c;文章内总结了常见的提问问题&#xff0c;旨在为广大学子模拟出更贴合实际的面试问答场景。在这篇文章中&#xff0c;可以点击题目直达问题答案处&#xff0c;方便查找问题寻找答案。节约大家的时间。通过对这…...

Java中Maven的依赖管理

依赖介绍 是指当前项目运行所需要的jar包&#xff0c;一个项目中可以引入多个依赖 配置 在pom.xml中编写<dependencies>标签 在<dependencies>中使用<dependency>引入标签 定义坐标的groupId、rtifactId、version 点击刷新按钮、引入新坐标 例如引入下…...

Github新手入门使用方法

**存在问题&#xff1a;**新手如何快速入门github&#xff0c;能够下载开源文件&#xff0c;并且修改后更新远程github仓库&#xff1b; 解决方案&#xff1a; 参考&#xff1a; http://www.360doc.com/content/24/0301/12/60419_1115656653.shtml https://blog.csdn.net/gongd…...

期权隐含波动率到底是什么意思?

今天期权懂带你了解期权隐含波动率到底是什么意思&#xff1f;期权隐含波动率解析。通俗的说&#xff0c;期权隐含波动率是在期权市场中买家和卖家对于&#xff0c;某一期权合约价格变动幅度大小的判断。 期权隐含波动率到底是什么意思&#xff1f; 隐含波动率是根据期权市场价…...

28、Flink 为管理状态自定义序列化

为管理状态自定义序列化 a&#xff09;概述 对状态使用自定义序列化&#xff0c;包含如何提供自定义状态序列化程序、实现允许状态模式演变的序列化程序。 b&#xff09;使用自定义状态序列化程序 注册托管 operator 或 keyed 状态时&#xff0c;需要 StateDescriptor 来指…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...