数据库(MySQL)—— 事务

数据库(MySQL)—— 事务

  • 什么是事务
  • 事务操作
    • 未控制事务
    • 测试异常情况
  • 控制事务一
    • 查看/设置事务提交方式:
    • 提交事务
    • 回滚事务
  • 控制事务二
    • 开启事务
    • 提交事务
    • 回滚事务
  • 并发事务问题
    • 脏读(Dirty Read)
    • 不可重复读(Non-Repeatable Read)
    • 幻读(Phantom Read)
    • 丢失更新(Lost Update)
  • 并发事务问题演示及事务隔离级别

我们今天来学习MySQL中的事务:

什么是事务

MySQL中的事务(Transaction)是一个逻辑上不可分割的工作单元,由一系列数据库操作组成,这些操作要么全部成功执行,要么全部不执行。事务的主要目的是为了维护数据库的一致性和完整性,尤其是在多用户同时访问和修改数据的并发环境下。

事务具备以下四个关键特性,即ACID特性:

  1. 原子性(Atomicity):事务是一个原子操作,事务中的所有操作要么全部完成,要么完全不起作用。如果事务中任何一部分操作失败,整个事务都会被回滚,仿佛从未发生过。
  2. 一致性(Consistency):事务执行前后,数据库从一种合法的状态转换到另一种合法的状态。即使在事务执行期间出现错误,数据库也应该保持一致的状态,不因事务失败而残留部分结果。
  3. 隔离性(Isolation):并发执行的事务之间互不干扰,一个事务内部的操作对其他事务是不可见的,直到该事务完成并提交。MySQL通过不同的事务隔离级别来实现这一特性,如读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)和串行化(SERIALIZABLE)。
  4. 持久性(Durability):一旦事务被提交,它对数据库的更改应该是永久性的,即使系统发生故障也不会丢失。这意味着事务的结果会被稳定地存储在数据库中。

在MySQL中,特别是使用InnoDB存储引擎时,可以通过BEGIN或START TRANSACTION语句显式地开始一个事务,使用COMMIT语句提交事务,以确认所有更改,或者使用ROLLBACK语句回滚事务,取消所有在事务中做出的更改。此外,还可以通过设置事务的隔离级别来调整不同事务之间的可见性,以适应不同的应用场景需求。

举个例子:
张三给李四转账1000块钱,张三银行账户的钱减少1000,而李四银行账户的钱要增加1000。 这一组操作就必须在一个事务的范围内,要么都成功,要么都失败。
在这里插入图片描述正常情况: 转账这个操作, 需要分为以下这么三步来完成 , 三步完成之后, 张三减少1000, 而李四增加1000, 转账成功:
在这里插入图片描述异常情况: 转账这个操作, 也是分为以下这么三步来完成 , 在执行第三步是报错了, 这样就导致张三减少1000块钱, 而李四的金额没变, 这样就造成了数据的不一致, 就出现问题了。
在这里插入图片描述为了解决上述的问题,就需要通过数据的事务来完成,我们只需要在业务逻辑执行之前开启事务,执行完毕后提交事务。如果执行过程中报错,则回滚事务,把数据恢复到事务开始之前的状态:
在这里插入图片描述

注意: 默认MySQL的事务是自动提交的,也就是说,当执行完一条DML语句时,MySQL会立即隐式的提交事务。

事务操作

数据准备:

drop table if exists account;

create table account(
id int primary key AUTO_INCREMENT comment 'ID',
name varchar(10) comment '姓名',
money double(10,2) comment '余额'
) comment '账户表';

insert into account(name, money) VALUES ('张三',2000), ('李四',2000);

未控制事务

测试正常情况:

-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';

在这里插入图片描述

测试异常情况

我们把数据都恢复到2000:

update account set money = 2000;

然后再次一次性执行下面的SQL语句:

-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';
出错了....
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';

在这里插入图片描述
(“出错了…” 这句话不符合SQL语法,执行就会报错)

检查最终的数据情况, 发现数据在操作前后不一致了:
在这里插入图片描述

控制事务一

查看/设置事务提交方式:

SELECT @@autocommit ;
SET @@autocommit = 0 ;

在MySQL中,SELECT @@autocommit;SET @@autocommit = 0; 是用来查看和设置当前会话的自动提交状态的命令。

  • SELECT @@autocommit;
    这条命令用于查询当前会话的自动提交(autocommit)设置。@@autocommit是一个系统变量,表示是否启用自动提交模式。如果返回值为1,意味着自动提交是开启的,即每次执行完一条SQL语句后,改动会立即保存到数据库中,成为永久性的变更。如果返回值为0,则表示自动提交是关闭的,你需要手动控制事务的提交与回滚。
    在这里插入图片描述
  • SET @@autocommit = 0;
    这条命令用于设置当前会话的自动提交模式为关闭状态。将@@autocommit的值设为0后,意味着在该会话中执行的SQL语句不会自动提交,直到你显式执行COMMIT命令才将事务中的更改永久保存。这样可以让你在一系列操作之间保持数据的一致性,便于实现事务的原子性、一致性、隔离性和持久性(ACID特性)。在需要手动控制事务边界的应用场景中非常有用。
    在这里插入图片描述

提交事务

此时我们又把数据恢复到2000,又执行那三条语句:
在这里插入图片描述我们查看结果发生变化了,但是这只是针对当前会话,如果我们重新开一个会话,就会发现数据没有发生变化,这里我用Navicat重开一个会话:
在这里插入图片描述
但是如果我执行commit,提交之后:
在这里插入图片描述
再在Navicat中查询结果:
在这里插入图片描述

所以我们设置提交模式为非自动的时候,如果我们想要我们的提交彻底生效,要记得执行commit

回滚事务

如果我在事务的流程当中出错了:
在这里插入图片描述
可以执行ROLLBACK操作,使数据回到开始前的状态:
在这里插入图片描述

控制事务二

开启事务

START TRANSACTIONBEGIN ; 1

提交事务

COMMIT;

回滚事务

ROLLBACK;

举个例子:

-- 开启事务
start transaction;

-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';
-- 如果正常执行完毕, 则提交事务
commit;

-- 如果执行过程中报错, 则回滚事务
-- rollback;

在这里插入图片描述

并发事务问题

并发事务问题是数据库管理系统中常见的挑战,特别是在多用户环境下,不同的事务可能同时对相同的数据进行读取或修改,从而引发以下几种典型的问题:

  1. 脏读(Dirty Read):事务A读取了事务B尚未提交的数据,如果事务B随后进行了回滚,那么事务A读取到的就是无效的“脏”数据。
  2. 不可重复读(Non-Repeatable Read):在同一个事务内,两次相同的查询返回了不同的结果,这是因为在两次查询之间,有其他事务提交了对该数据的修改或删除操作。
  3. 幻读(Phantom Read):在一个事务内,第一次查询时没有特定条件的某些行,但是在同一事务内的第二次查询时,由于其他事务插入了新行,这些新行就仿佛“幻影”一样出现了。
  4. 丢失更新(Lost Update):两个事务同时读取同一条数据,然后基于原始数据进行修改并提交,如果数据库系统没有适当的并发控制机制,后提交的事务可能会覆盖前一个事务的更改,导致前一个事务的更新丢失。

脏读(Dirty Read)

场景:事务A正在更新一条记录但尚未提交,事务B在此时读取了事务A更改但未提交的数据。

  • 事务A:

    BEGIN;
    UPDATE accounts SET salary = salary - 100 WHERE id = 1; -- 减少张三账户100元,但没提交
    
  • 事务B (同时进行):

    SELECT salary FROM accounts WHERE id = 1; -- 查询张三账户余额,看到减少了100元
    
  • 假设:事务A因为某种原因执行了ROLLBACK。

  • 结果:事务B读取到了实际上未生效的“脏”数据(减少了100元的余额),而最终张三的账户余额并未发生变化。

不可重复读(Non-Repeatable Read)

场景:在同一个事务内,两次查询返回了不同的结果,因为中间有其他事务提交了修改。

  • 事务A:

    BEGIN;
    SELECT salary FROM accounts WHERE id = 1; -- 第一次查询张三余额为500元
    
  • 事务B (并发执行,并提交):

    UPDATE accounts SET salary = salary + 100 WHERE id = 1; -- 给张三账户加100元并提交
    
  • 事务A 继续:

    SELECT salary FROM accounts WHERE id = 1; -- 第二次查询张三余额变为600元
    
  • 结果:事务A在同一个事务内两次查询同一数据得到不同结果,违反了可重复读原则。

幻读(Phantom Read)

场景:在一个事务内,两次相同的查询因其他事务插入新行而返回不同的行数。

  • 事务A:

    BEGIN;
    SELECT * FROM orders WHERE customer_id = 1; -- 初始查询客户1的订单有5个
    
  • 事务B (并发执行,并提交):

    INSERT INTO orders(customer_id, order_date) VALUES(1, CURDATE()); -- 给客户1新增一个订单并提交
    
  • 事务A 继续:

    SELECT * FROM orders WHERE customer_id = 1; -- 再次查询客户1的订单,现在有6个
    
  • 结果:事务A第二次查询时出现了额外的“幻影”行,即原本不存在但在查询过程中被其他事务插入的记录。

丢失更新(Lost Update)

场景:两个事务同时修改同一数据,后提交的事务覆盖了前一个事务的更改。

  • 事务A:

    BEGIN;
    SELECT salary FROM accounts WHERE id = 1; -- 张三余额为500元
    
  • 事务B (几乎同时开始,并提交快):

    BEGIN;
    SELECT salary FROM accounts WHERE id = 1; -- 也看到张三余额为500元
    UPDATE accounts SET salary = salary + 100 WHERE id = 1; -- 增加100元并提交
    
  • 事务A 继续, 未知事务B已更新:

    UPDATE accounts SET salary = salary - 100 WHERE id = 1; -- 减少100元并提交,基于旧值操作
    
  • 结果:尽管事务B给张三增加了100元,但事务A的减操作基于事务B之前的数据,最终张三的账户余额没有变化,事务B的更新被事务A无意中“丢失”了。

为了解决这些问题,数据库系统提供了不同的事务隔离级别,分别是:

  • 读未提交(Read Uncommitted):最低的隔离级别,允许脏读、不可重复读和幻读。
  • 读已提交(Read Committed):只允许不可重复读和幻读,禁止脏读。
  • 可重复读(Repeatable Read):MySQL的InnoDB默认隔离级别,禁止脏读和不可重复读,但可能出现幻读。
  • 串行化(Serializable):最高的隔离级别,通过完全锁定读取和更新的行,避免了脏读、不可重复读和幻读,但可能导致大量锁竞争,影响性能。

并发事务问题演示及事务隔离级别

在这里插入图片描述图中打钩的表示在此模式下,该问题可能发生,打叉表示可防止此问题发生。

SELECT @@TRANSACTION_ISOLATION;

在这里插入图片描述
这里我们要看脏读,首先要把事务的隔离级别设置为Read uncommitted,设置事务隔离级别用下面的代码:

SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED |
READ COMMITTED | REPEATABLE READ | SERIALIZABLE }

session是设置当前对话,global是全局。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【LLM第二篇】stable diffusion扩散模型、名词解释

最近在整理大模型的相关资料,发现了几个名词,不是很懂,这里整理一下: stable diffusion(SD)模型: 扩散模型(Diffusion model)的一种,主要用于生成高质量的图像&#xf…

分布式与一致性协议之一致哈希算法(三)

一致哈希算法 如何使用一致哈希算法实现哈希寻址 我们一起来看一个例子,对于1000万个key的3节点KV存储,如果我们使用一致哈希算法增加1个节点,即3节点集群变为4节点集群,则只需要迁移24.3%的数据,如代码所示 package mainimpor…

IoTDB 入门教程 基础篇⑧——数据库管理工具 | IDEA 连接 IoTDB

文章目录 一、前文二、下载iotdb-jdbc三、IDEA驱动四、IDEA连接数据库五、数据库应用六、其他 一、前文 IoTDB入门教程——导读 二、下载iotdb-jdbc 下载地址org/apache/iotdb/iotdb-jdbc:https://maven.proxy.ustclug.org/maven2/org/apache/iotdb/iotdb-jdbc/ 本…

Hive大数据任务调度和业务介绍

目录 一、Zookeeper 1.zookeeper介绍 2.数据模型 3.操作使用 4.运行机制 5.一致性 二、Dolphinscheduler 1.Dolphinscheduler介绍 架构 2.架构说明 该服务内主要包含: 该服务包含: 3.FinalShell主虚拟机启动服务 4.Web网页登录 5.使用 5-1 安全中心…

022、Python+fastapi,第一个Python项目走向第22步:ubuntu 24.04 docker 安装mysql8集群、redis集群(三)

这次来安装mysql8了,以前安装不是docker安装,这个我也是第一次,人人都有第一次嚒 前言 前面的redis安装还是花了点时间的,主要是网上教程,各有各的好,大家千万别取其长处,个人觉得这个环境影响…

一、Mysql索引的底层数据结构与算法

Mysql索引的底层数据结构与算法 前言一、索引数据结构为什么 MySQL 的索引要使用 B 树而不是其他树形结构?比如 B 树?为什么InnoDB存储引擎选择使用Btree索引结构? 二、索引分类思考:以下SQL语句,那个执行效率高?为什么&#xf…

Stable Diffusion AI绘画

我们今天来了解一下最近很火的SD模型 ✨在人工智能领域,生成模型一直是研究的热点之一。随着深度学习技术的飞速发展,一种名为Stable Diffusion的新型生成模型引起了广泛关注。Stable Diffusion是一种基于概率的生成模型,它可以学习数据的潜…

数据仓库实验三:分类规则挖掘实验

目录 一、实验目的二、实验内容和要求三、实验步骤1、创建数据库和表2、决策树分类规则挖掘(1)新建一个 Analysis Services 项目 jueceshu(2)建立数据源视图(3)建立挖掘结构 DST.dmm(4&#xff…

Qt模型视图代理之QTableView应用的简单介绍

往期回顾 Qt绘图与图形视图之绘制带三角形箭头的窗口的简单介绍-CSDN博客 Qt绘图与图形视图之Graphics View坐标系的简单介绍-CSDN博客 Qt模型视图代理之MVD(模型-视图-代理)概念的简单介绍-CSDN博客 Qt模型视图代理之QTableView应用的简单介绍 一、最终效果 二、设计思路 这里…

【Android学习】日期和时间选择对话框

实现功能 实现日期和时间选择的对话框&#xff0c;具体效果可看下图(以日期为例) 具体代码 1 日期对话框 1.1 xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android&quo…

EPAI手绘建模APP资源管理和模型编辑器2

g) 矩形 图 26模型编辑器-矩形 i. 修改矩形的中心位置。 ii. 修改矩形的长度和宽度。 h) 正多边形 图 27模型编辑器-内接正多边形 图 28模型编辑器-外切正多边形 i. 修改正多边形的中心位置。 ii. 修改正多边形中心距离端点的长度。 iii. 修改正多边形的阶数。阶数为3&…

排序算法之堆排序

首先在了解堆排序之前我们先来回顾一下什么叫做堆吧&#xff01; 基本概念 堆&#xff08;Heap&#xff09;&#xff1a;是一种特殊的完全二叉树&#xff0c;其中每个节点的值都大于或等于&#xff08;大顶堆&#xff09;或小于或等于&#xff08;小顶堆&#xff09;其子节点的…

活动图与状态图:UML中流程图的精细化表达——专业解析系统动态性与状态变迁

流程图是一种通用的图形表示法&#xff0c;用以展示步骤、决策和循环等流程控制结构。它通常用于描述算法、程序执行流程或业务过程&#xff0c;关注于任务的顺序执行。流程图强调顺序、分支和循环&#xff0c;适用于详细说明具体的处理步骤&#xff0c;图形符号相对基础和通用…

ubuntu搭建kms服务器

1.下载kms开源包(如果提示找不到wget命令的话:apt install wget): wget https://github.com/Wind4/vlmcsd/releases/download/svn1111/binaries.tar.gz2.解压: tar -xzvf binaries.tar.gz接着cd 进入 Linux/intel/static/ 文件夹下: 3.选择对应的文件&#xff0c;这里我们选…

onedrive下載zip檔案有20G限制,如何解決

一般來說&#xff0c;OneDrive網頁版對文件下載大小的限制如下圖所示&#xff0c;更多資訊&#xff0c;請您參考這篇文章&#xff1a;OneDrive 和 SharePoint 中的限制 - Microsoft Support 因此我們推薦您使用OneDrive同步用戶端來同步到本地電腦&#xff0c;您也可以選擇只同…

C语言——rand函数

一、rand函数 这是一个在 C 标准库 <stdlib.h> 中定义的函数&#xff0c;用于生成伪随机数&#xff0c;默认情况下&#xff0c;它生成从 0 到 RAND_MAX 的伪随机数&#xff0c;其中 RAND_MAX 是一个常数&#xff0c;通常是 32767。 1、函数原型&#xff1a; 2、函数返回…

C#中.net8WebApi加密解密

尤其在公网之中&#xff0c;数据的安全及其的重要&#xff0c;除过我们使用jwt之外&#xff0c;还可以对传送的数据进行加密&#xff0c;就算别人使用抓包工具&#xff0c;抓到数据&#xff0c;一时半会儿也解密不了数据&#xff0c;当然&#xff0c;加密也影响了效率&#xff…

【Qt问题】VS2019 Qt win32项目如何添加x64编译方式

解决办法&#xff1a; 注意改为x64版本以后&#xff0c;要记得在项目属性里&#xff0c;修改Qt Settings、对应的链接include、lib等 参考文章 VS2019 Qt win32项目如何添加x64编译方式_vs2019没有x64-CSDN博客 有用的知识又增加了~

www.fastssh.com SSH over WebSockets with CDNs

https://www.fastssh.com/page/create-ssh-cdn-websocket/server/这其实不是标准的websocket报文(服务器响应报文无Sec-Websocket-Accept字段)&#xff0c;所以无法使用github.com/gorilla/websocket包&#xff1a;GET / HTTP/1.1 Host: hostname:8080 User-Agent: Go-http-cli…

43 单例模式

目录 1.什么是单例模式 2.什么是设计模式 3.特点 4.饿汉和懒汉 5.峨汉实现单例 6.懒汉实现单例 7.懒汉实现单例&#xff08;线程安全&#xff09; 8.STL容器是否线程安全 9.智能指针是否线程安全 10.其他常见的锁 11.读者写者问题 1. 什么是单例模式 单例模式是一种经典的&a…