Mysql的事务

MySQL中的事务是一组数据库操作,这些操作被视为单个逻辑单元并且被当做原子操作执行,这意味着它们要么全部成功,要么全部失败,没有中间状态。事务通常用于确保数据库中的数据完整性和一致性。

在MySQL中,事务可以使用以下命令启动和结束:

BEGIN或START TRANSACTION:用于开始一个新的事务。
COMMIT:用于提交事务,即将所做的更改保存到数据库中。
ROLLBACK:用于撤销事务,即回滚到事务开始之前的状态。
复制代码

MySQL数据库本身是自带事务,MySQL在执行SQL语句的时候是【自动提交事务】,保证SQL语句正常执行并且更改数据库中数据,MySQL中事务主要就是保证数据库中数据安全性,通过事务的特征(ACID)已到达SQL语句操作数据的安全性

MySQL的事务其实就是一组逻辑性操作,这个操作的要求要么都成功,要么都失败

因为MySQL是自动事务,所以对于某些操作需要手动开启事务才可以达到效果

数据的准备

# 准备一些事务数据
# 创建一张账户表
create table account(
    id int PRIMARY KEY AUTO_INCREMENT,
    name varchar(20) NOT NULL,
    money double
);

# 插入数据
INSERT INTO account(name,money) values
('zs',10000),('ls',10000);

select * from account;
复制代码

MySQL中事务就是保证数据库内表中数据被SQL语句修改之后数据安全问题,使用就是事务提供特性(ACID),模拟一个场景:利用account账户进行转账和收款的过程

提供一组操作 zs 转账1000【money - 1000】 ls 进账 1000 【money+1000】

MySQL使用事务原则特性就是保证 SQL语句的执行要么都成功,要么都失败

提供一组操作成功 zs 余额 9000 ls 余额 11000

提供一组操作失败 zs 余额 10000 ls 余额 10000

提供一组操作是不会出现 zs 余额 9000 ls余额10000 或 zs 余额10000 ls余额 11000

正常转账版本

# 假设 zs 和 ls 谈成了一笔大面买 交易金额是1000元
# 需要从 zs 账户中将1000元扣除  ls 账户中需要加入这1000
# zs 需要转账 1000 
UPDATE account SET money = money-1000 WHERE name = 'zs'; -- 模拟转账

# ls 需要进账 1000
UPDATE account SET money = money+1000 WHERE name = 'ls'; -- 模拟收款

# 账户查询
SELECT * FROM account;
复制代码

2021-12-17_0848592021-12-17_084859

提供一个异常转账的操作

# 准备一些事务数据
# 创建一张账户表
create table account(
    id int PRIMARY KEY AUTO_INCREMENT,
    name varchar(20) NOT NULL,
    money double
);

# 插入数据
INSERT INTO account(name,money) values
('zs',10000),('ls',10000);

select * from account;

# 假设 zs 和 ls 谈成了一笔大面买 交易金额是1000元
# 需要从 zs 账户中将1000元扣除  ls 账户中需要加入这1000
# zs 需要转账 1000 
UPDATE account SET money = money-1000 WHERE name = 'zs'; -- 模拟转账

/*
模拟 【数据库因为zs用户转账之后数据出现问题】
zs 转账之后出现问题 ---》 突然间出现【断电、火灾、数据库崩溃、各种操作异常】

导致 ls的收款语句【没有执行】,程序直接退出  ls账户没有任何金额进入

MySQL是自动事务,提交到MySQL中数据库操作一旦执行成功就“永久生效”
此时面临这样场景,MySQL中自动事务就无法满足需求

事务最主要特点就是:【要么都成功,要么都失败】
而现在就违背了这个原则: zs 转账之后扣款1000 但是出现问题,这1000元不应该扣款成功,而是返回给zs账户。

像这样对于数据库中数据修改的操作 建议将自动事务修改为手动事务
*/

# ls 需要进账 1000
UPDATE account SET money = money+1000 WHERE name = 'ls'; -- 
模拟收款

# 账户查询
SELECT * FROM account;
复制代码

2021-12-17_0904082021-12-17_090408

可以对MySQL进行手动事务的开启

# 准备一些事务数据
# 创建一张账户表
create table account(
    id int PRIMARY KEY AUTO_INCREMENT,
    name varchar(20) NOT NULL,
    money double
);

# 插入数据
INSERT INTO account(name,money) values
('zs',10000),('ls',10000);

select * from account;

#手动开启事务
start TRANSACTION; -- 这个语句作用就是开启“手动”事务
/*
当上述语句执行完毕之后,后续语句执行都是“手动事务”操作
手动事务中提供两个核心操作
commit 提交 【在确认操作无误的前提下,使用commit可以将SQL语句提交给数据库执行并永久生效】
rollback 回滚 【当执行SQL语句出现问题的时候,就可以使用rollbacl执行回滚操作,将SQL语句操作回滚到之前一个状态】
*/

# 假设 zs 和 ls 谈成了一笔大面买 交易金额是1000元
# 需要从 zs 账户中将1000元扣除  ls 账户中需要加入这1000
# zs 需要转账 1000 
UPDATE account SET money = money-1000 WHERE name = 'zs'; -- 模拟转账
/*
模拟 【数据库因为zs用户转账之后数据出现问题】
zs 转账之后出现问题 ---》 突然间出现【断电、火灾、数据库崩溃、各种操作异常】

导致 ls的收款语句【没有执行】,程序直接退出  ls账户没有任何金额进入

MySQL是自动事务,提交到MySQL中数据库操作一旦执行成功就“永久生效”
此时面临这样场景,MySQL中自动事务就无法满足需求

事务最主要特点就是:【要么都成功,要么都失败】
而现在就违背了这个原则: zs 转账之后扣款1000 但是出现问题,这1000元不应该扣款成功,而是返回给zs账户。

像这样对于数据库中数据修改的操作 建议将自动事务修改为手动事务
*/
ROLLBACK; -- 回滚
# ls 需要进账 1000
UPDATE account SET money = money+1000 WHERE name = 'ls'; -- 模拟收款


#COMMIT; -- 提交

# 账户查询
SELECT * FROM account;
复制代码

2021-12-17_0919292021-12-17_091929

开启手动事务之后如果转账成功

# 准备一些事务数据
# 创建一张账户表
create table account(
    id int PRIMARY KEY AUTO_INCREMENT,
    name varchar(20) NOT NULL,
    money double
);

# 插入数据
INSERT INTO account(name,money) values
('zs',10000),('ls',10000);

select * from account;

#手动开启事务
start TRANSACTION; -- 这个语句作用就是开启“手动”事务
/*
当上述语句执行完毕之后,后续语句执行都是“手动事务”操作
手动事务中提供两个核心操作
commit 提交 【在确认操作无误的前提下,使用commit可以将SQL语句提交给数据库执行并永久生效】
rollback 回滚 【当执行SQL语句出现问题的时候,就可以使用rollbacl执行回滚操作,将SQL语句操作回滚到之前一个状态】
*/

# 假设 zs 和 ls 谈成了一笔大面买 交易金额是1000元
# 需要从 zs 账户中将1000元扣除  ls 账户中需要加入这1000
# zs 需要转账 1000 
UPDATE account SET money = money-1000 WHERE name = 'zs'; -- 模拟转账
/*
模拟 【数据库因为zs用户转账之后数据出现问题】
zs 转账之后出现问题 ---》 突然间出现【断电、火灾、数据库崩溃、各种操作异常】

导致 ls的收款语句【没有执行】,程序直接退出  ls账户没有任何金额进入

MySQL是自动事务,提交到MySQL中数据库操作一旦执行成功就“永久生效”
此时面临这样场景,MySQL中自动事务就无法满足需求

事务最主要特点就是:【要么都成功,要么都失败】
而现在就违背了这个原则: zs 转账之后扣款1000 但是出现问题,这1000元不应该扣款成功,而是返回给zs账户。

像这样对于数据库中数据修改的操作 建议将自动事务修改为手动事务
*/
#ROLLBACK; -- 回滚
# ls 需要进账 1000
UPDATE account SET money = money+1000 WHERE name = 'ls'; -- 模拟收款


COMMIT; -- 提交

# 账户查询
SELECT * FROM account;
复制代码

2021-12-17_0925222021-12-17_092522

事务的原则(特征)

原子性(Atomicity)是指事务是一个不可分割的单位,事务中操作要么都发生(成功),要么不发生(失败)

例如: 转账案例
操作成功 zs money = 9000(-1000) ls money = 11000(+1000)

操作失败 zs money = 10000 ls money = 10000

不可能发生 zs money = 9000(-1000) ls money = 10000

​ 或 zs money = 10000 ls money =11000

一致性(Consistency)是指事务前后数据完成性必须保持一致

例如: 无论发生什么(成功/失败)数据的总和使用保持20000

​ 不可能出现 zs money = 9000(-1000) ls money = 10000 (+10000)总和 19000

​ 不可能出现 zs money = 10000(-1000) ls money = 11000 (+10000)总和 21000

隔离性(Isolation)是指事务在多个用户并发操作数据库时,一个用户的事务是不能其他用户所干扰,多并发事务之间的数据是相互隔离的

持久性(Durability)是指一个事务一旦被提交,它对数据库中数据修改永久的,就算接下来数据库发生故障也不会对数据造成影响

事务操作和隔离性问题

事务操作之设置回滚点

当插入大量数据的时候(1亿条数据),事务的原则要么都成功,要么都是失败

如果你保持这个事务原则,假设插入到7000W条数据的时候,程序崩溃了,事务的回滚执行会将之前所有插入都回滚,这样一来就你需要从第一条插入,这种无脑回滚对于操作是有影响,所以为了解决这样问题,可以在SQL语句或操作代码中设置【回滚点】,一旦出现错误,不是回滚所有数据,而是回滚到这个回滚点设置的位置

设置回滚点 -----》 saveponit 回滚点的名字

回滚数据 -----》 rollback to 回滚点的名字

#手动开启事务
start TRANSACTION; -- 这个语句作用就是开启“手动”事务

# zs 需要转账 1000 
UPDATE account SET money = money-1000 WHERE name = 'zs'; -- 模拟转账
UPDATE account SET money = money-1000 WHERE name = 'zs'; 
UPDATE account SET money = money-1000 WHERE name = 'zs'; 
UPDATE account SET money = money-1000 WHERE name = 'zs'; 

#设置一个回滚点
SAVEPOINT zrollback;
#操作都失败了
UPDATE account SET money = money-1000 WHERE name = 'zs'; -- 模拟转账
UPDATE account SET money = money-1000 WHERE name = 'zs'; 
UPDATE account SET money = money-1000 WHERE name = 'zs'; 
UPDATE account SET money = money-1000 WHERE name = 'zs'; 

# 回滚到指定的回滚点之前
ROLLBACK TO zrollback;
# 账户查询
SELECT * FROM account;
复制代码

隔离性问题

MySQL中事务一共有四种隔离性【级别是从低到高】

级别名字隔离级别(操作英文)脏读不可重复读幻读数据库默认隔离和级别
1读未提交read uncommitted
2读已提交read committed
3可重复读repeatable readMySQL
4串行化serializable

如果在不考虑事务的隔离性的前提下就会出现【脏读、不可重复读、幻读】,事务的隔离性的理想状态,就是在操作事务时出现互不干扰的结果

如果需使用MySQL数据库避免这三个问题【脏读、不可重复读、幻读】,只能开启最高隔离级别“串行化”,如果一旦开启串行化,所有MySQL客户端的操作都是“串行”效果只要一个客户端在操作数据库,没有执行commit之前,剩余客户端的操作都要等待

隔离级别越高,性能越差,特别是“串行化”,正常开发中MySQL的默认隔离级别就可以了

#查询和修改数据库隔离级别
#查询
select @@tx_isolation;  --》 mysql5.7 但是 mysql8.0失效
select @@transaction_isolation; --》 mysql8.0查询
#修改隔离级别
read uncommitted(读未提交)	read committed(读已提交) 
repeatable read(可重复读)	serializable(串行化)
复制代码

以下的演示中都需要开启两个创建A窗口和B窗口

演示脏读

一个事务中读取到另外一个事务没有提交数据就叫做脏读

PS:演示中需要开启 read uncommitted(读未提交) 隔离级别

数据准备

create table T(
    ID int,
    name varchar(255)
    );
INSERT INTO T(id,name) values(1,'牛A'),(1,'牛B'),(1,'牛C');
复制代码

文末扫码领取福利!

  1. 先在A、B窗口中确认隔离级别
#查询隔离级别
select @@transaction_isolation;
复制代码
  1. 设置A窗口的隔离级别为read uncommitted(读未提交)
set session transaction isolation level read uncommitted;
复制代码
  1. A、B窗口同时开启手动事务
start transaction;
复制代码
  1. 在B窗口中插入数据
INSERT INTO T values(4,'牛D');
复制代码
  1. 在A窗口中进行查询
select * from T;
复制代码

这时如果没有事务之间隔离性,那么B窗口中事务结果就会出现在A窗口中,因为现在是手动事务,在B窗口中执行的操作并没有做任何提交,但是在A窗口中可以查询出来这个就是“脏读(dirty read)”

演示不可重复读

数据准备

create table T1(
    ID int,
    name varchar(255)
    );
INSERT INTO T1(id,name) values(1,'牛A'),(1,'牛B'),(1,'牛C');
复制代码

不可重复读:在一个事务里面,同一条语句,两次查询的结果不一致

  1. 先在A、B窗口中确认隔离级别
#查询隔离级别
select @@transaction_isolation;
复制代码
  1. 设置A、B窗口的隔离级别为read committed(读已提交)
set session transaction isolation level read committed;
复制代码
  1. A、B窗口同时开启手动事务
start transaction;
```·

4. 在B窗口中执行更新操作

````sql
update t1 set name = '不牛' where ID = 1;
复制代码
  1. 在A窗口中执行操作操作【此时得到是结果(牛A、牛B、牛C)此时避免了脏读】
select * from t1;
复制代码
  1. 在B窗口中执行了提交操作
COMMIT
复制代码
  1. 在A窗口中执行操作操作【此时得到结果是(不牛、不牛、不牛)】
select * from t1;
复制代码

执行了两次selec得到结果是不一样【在同一个事务中】,这个效果就是不可重复读

演示幻读

数据准备

create table T2(
    ID int PRIMARY KEY, -- 这个列设置为主键
    name varchar(255)
    );
INSERT INTO t2(id,name) values(1,'牛A'),(2,'牛B'),(3,'牛C');
复制代码

幻读的【错误】理解:幻读事务A执行两次select操作得到不同结果集,即select1得到10条记录,select2得到11条记录,这个操作就是幻读

这里其实并不是幻读,这是不可重复读取的一种,只要在 【读未提交、读已提交】隔离级别下都会出现,而在MySQL默认隔离级别下是不会出现的

幻读的正确理解:并不是说读取获取结果集不同,幻读侧重的方面是某一次select操作得到结果所表现的数据状态无法支撑后续业务操作。更具体一些:select查询之后某记录是否存在,不存在,准备插入数据时,无法执行insert插入提示数据已存在,这效果才是幻读

  1. 先在A、B窗口中确认隔离级别
#查询隔离级别
select @@transaction_isolation;
复制代码
  1. 设置A、B窗口的隔离级级别repeatable read、(可重复读)
set session transaction isolation level repeatable read;
复制代码
  1. A、B窗口同时开启手动事务
start transaction;
复制代码
  1. 在A窗口先执行一次查询
   select * from  t2;
复制代码
  1. 在B窗口中出入一条数据并提交
   insert into t2 values(4,'牛D');
   COMMIT
复制代码
  1. 在A执行查询操作【上一次的查询要进行提交 读取到都是插入之前的结果】
   select * from  t2;
复制代码
  1. 在A窗口中在插入数据【数据插入是失败的,因为数据已经存在】
   insert into t2 values(4,'牛D');
复制代码

演示串行化【就是所有问题都不出现,但是效率极低】

数据准备

create table T3(
    ID int PRIMARY KEY, -- 这个列设置为主键
    name varchar(255)
    );
INSERT INTO t3(id,name) values(1,'牛A'),(2,'牛B'),(3,'牛C');
复制代码
  1. 先在A、B窗口中确认隔离级别
#查询隔离级别
select @@transaction_isolation;
复制代码
  1. 设置A、B窗口的隔离级级别serializable (串行化)
set session transaction isolation level serializable ;
复制代码
  1. A、B窗口同时开启手动事务
start transaction;
复制代码
  1. 在B窗口中插入数据
   insert into t3 values(4,'牛D');
复制代码
  1. 在A窗口中查询
 select * from  t3;
复制代码

此时A窗口中是不会出现数据的,只有B窗口提供commit,A窗口才会执行查询出数据

千锋大数据Hadoop全新增强版-先导片

 

 

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

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

相关文章

玩转css逐帧动画,努力成为更优质的Ikun~

🎉 一、前言 css3的animation想必大家都知道吧,那 steps 逐帧动画你知道吗?对于我来说,实际工作及练习中也很少用到这种跳跃式变化的动画,而它start和end的解释又比较“不说人话”,以前用到steps动画的时候…

Linux - 第23节 - Linux高级IO(一)

目录 1.IO的基本概念 2.钓鱼五人组 3.五种IO模型 3.1.阻塞IO 3.2.非阻塞IO 3.3.信号驱动IO 3.4.IO多路转接 3.5.异步IO 4.高级IO重要概念 4.1.同步通信 VS 异步通信 4.2.阻塞 VS 非阻塞 5.其他高级IO 6.阻塞IO 7.非阻塞IO 7.1.fcntl函数介绍 7.2.fcntl函数的使…

MobPush 推送查询API

IP绑定 工作台可以绑定服务器IP地址,未绑定之前所有IP均可进行REST API的调用,绑定后进仅绑定的IP才有调用权限。 设备信息查询接口 根据RegistrationId查询设备信息 接口地址 http://api.push.mob.com/device-v3/getById/{registrationId} 请求方式…

三种编码方式(费诺曼编码,霍夫曼编码,哈夫曼树编码)的简单解释和介绍

一. 费诺曼(Fano)编码是一种前缀编码,其基本原理是将出现频率较高的符号用短的编码表示,而出现频率较低的符号则用长的编码表示。通过这种方式进行编码,可以达到更好的压缩效果。 费诺曼编码的具体过程如下: 将要编码的符号按照…

一个小时入门 Android Compose 动画

0. 前言 前段时间对于Android中的Compose动画做了系统性的学习,相关文章发布在 Compose 动画 专栏里。系统性学完Compose动画后,又对此做了系统性的回顾,抽取其比较重要的部分,希望能帮助大家快速入门Compose动画,所…

ChatGPT新突破:打造自己的智能机器人控制系统

💖 作者简介:大家好,我是Zeeland,全栈领域优质创作者。📝 CSDN主页:Zeeland🔥📣 我的博客:Zeeland📚 Github主页: Undertone0809 (Zeeland) (github.com)&…

【论文速览】根据人脑fMRI信号重建图像 Image Reconstruction from human brain activity

文章目录 前言文章一研究背景主要方法部分实验结果总结与思考参考资料 文章二研究背景主要方法部分实验结果总结与思考 前言 人类的视觉神经系统对于真实世界的视觉刺激有着非凡的感知与理解能力,比如我们能够准确地识别物体距离和三维几何关系等,这是当…

三维数字沙盘交互大数据可视化GIS地理信息系统第十课

三维电子沙盘交互无人机倾斜摄影大数据可视化GIS地理信息系统第十课 设置system.ini 如下内容 Server122.112.229.220 userGisTest Passwordchinamtouch.com 该数据库中只提供 成都市火车南站附近的数据请注意,104.0648,30.61658 在SDK中自带了一个自定义的基础面…

pycharm和virtualBox虚拟机的安装(包括本地环境和远程环境配置)

目录 一、安装时需要的软件二、安装virtualBox三、安装pycharm四、创建pycharm本地环境五、创建pycharm远程环境 一、安装时需要的软件 Pycharm,jetbrains-agent-latest破解包(破解pycharm);镜像文件ubuntu20,虚拟机virtualBox …

Zellij – 颜值爆表,比tmux、screen更好用的多窗口终端

如果你曾经使用过多窗口终端,如tmux、screen,那么你可能对Zellij上手会更快。下面将介绍这个惊艳出众的多窗口终端利器。 一、Zellij 特点 Zellij最大的特点是支持插件,与WebAssembly编译兼容。与screen和tmux相比,Zellij是以细…

Linux 之Python 定制篇-APT 软件管理和远程登录

Linux 之Python 定制篇-APT 软件管理和远程登录 apt 介绍 apt 是Advanced Packaging Tool 的简称,是一款安装包管理工具。在Ubuntu 下,我们可以使用apt 命令进行软件包的安装、删除、清理等,类似于Windows 中的软件管理工具。 unbuntu 软件…

LVS-DR负载群集的优势和部署实例(我们都会在各自喜欢的事情里变得可爱)

文章目录 一、DR模式数据包流向分析二、DR模式的特点三、DR模式中需要解决的问题问题1解决方式 问题2解决方式 四、LVS-DR部署实例1.配置NFS共享存储器2.配置节点web服务(两台的配置相同)3.配置LVS负载调度器 一、DR模式数据包流向分析 1.Client 客户端…

《计算机网络——自顶向下方法》精炼——3.7(2)

读书有三到:谓心到,眼到,口到。——明朱熹 文章目录 对链接吞吐量的简化描述高带宽路径的TCP公平性 对链接吞吐量的简化描述 为了简化对一条TCP连接吞吐量的描述,我们首先忽略连接过程中处于慢启动状态的时间,因为这一…

chatgpt赋能python:Python将yyyymmdd转换成yyyy-mm-dd的方法

Python将yyyymmdd转换成yyyy-mm-dd的方法 Python语言不仅易于学习,而且是一种功能强大的语言,广泛应用于数据分析、人工智能和Web开发等领域。在实际开发过程中,我们经常遇到需要将日期格式转换为其他格式的需求。本文将介绍如何使用Python将…

Nginx rewrite

目录 一、location 1.location 匹配规则介绍 2. 实际网站使用中匹配规则 2.1第一个必选规则 2.2第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项 2.3第三个规则就是通用规则 3.location 匹配规则演示 2.1一般前缀匹配 2.2正则匹配 2.3正则…

电池状态估计 | Matlab实现利用卡尔曼滤波器估计电池充电状态

文章目录 效果一览文章概述研究内容程序设计参考资料效果一览 文章概述 电池状态估计 | Matlab实现利用卡尔曼滤波器估计电池充电状态 研究内容 目前,常用的电池模型有:数

斐波那契数列题解(非递归c++方法实现)

在做信奥赛(信息学奥赛)中的for循环题目时,有一道斐波那契数列,想到的第一个方法是使用递归求解;因为以往题目最多使用的就是递归形式,但鉴于该题目在for循环题目堆,所以就思考了一些新方法&…

仙境传说RO:添加限购物品刷新物品库存教程

仙境传说RO:添加限购物品刷新物品库存教程 大家好我是艾西,在游戏中我们会有普通的基础装备那么必然就会有到顶的套装,往往可能一套到顶的套装就可能霸服。那么就需要GM去做游戏的设定以及限制,上一篇文章中我给大家讲述了如果创…

RabbitMQ的基本概念

目录 1、MQ 的基本概念 1.1 MQ概述 1.2 MQ 的优势和劣势 1.3 MQ 的优势 1. 应用解耦 2. 异步提速 3. 削峰填谷 小结: 1.4 MQ 的劣势 1.5 常见的 MQ 产品 1.6 RabbitMQ 简介 1.7 JMS 1、MQ 的基本概念 1.1 MQ概述 MQ全称 Message Queue(消息队列&#…

火山引擎DataLeap的Catalog系统搜索实践(三):Learning to rank与后续工作

Learning to rank Learning to rank主要分为数据收集,离线训练和在线预测三个部分。搜索系统是一个Data-driven system,因此火山引擎DataLeap的Catalog系统设计之初就需要考虑数据收集。收集的数据可以用来评估和提升搜索的效果。数据收集和在线预测前面…