【数据库】事务、事务并发问题、并发事务隔离级别、及sql演示

文章目录

  • 一、事务
    • 1.1 事务简介 及 sql 操作
    • 1.2 事务的特性
  • 二、事务并发问题
  • 三、事务隔离级别
  • 四、sql 演示
    • 4.1 脏读
    • 4.2 不可重复读
    • 4.3 幻读
  • 五、演示代码


一、事务

1.1 事务简介 及 sql 操作

事务:数据库执行的一系列操作,这些操作要么全部执行,要么全部不执行
若要把多个操作放在一个事务范围内,需要手动 开启事务,提交事务,回滚事务

-- 查询事务提交方式
select @@autocommit;		-- 1. 自动提交,0. 手动提交
-- 设置事务手动提交
set @@autocommit = 0;
-- 提交事务
commit;
-- 回滚事务
rollback;
-- 开启事务
start transaction;	# 方式 1
begin;				# 方式 2

1.2 事务的特性

  • 原子性(Atomicity):事物是一组不可分割的最小操作单元。要么全部成功,要么全部失败
  • 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态
  • 隔离性(Isolation):事物在不受外部并发操作影响的独立环境下运行
  • 持久性(Durability):事务一旦提交或回滚,对数据库中的数据改变是永久的

二、事务并发问题

  1. 脏读一个事务读到另一个事务还没提交的数据
  2. 不可重复读一个事务先后读取同一条记录,但两读读取的数据不一致
  3. 幻读一个事务按条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据存在

假设有事务A、事务B、表 tb

脏读:    
        A 修改 tb 中的数据,但是还没有提交(commit)
        B 读 tb 中的数据,读到了未提交的数据

事务的操作只有提交了才会生效,刷新到磁盘中。由于事务A还没有提交,A的修改只写入了缓冲池,此时B读到了A修改的缓冲池的数据,读到了 “脏东西”。因为 A 不一定会提交,有可能是错误数据最后 rollback 回滚。


不可重复读:    
        A 先读了一条记录,发现是(1,2,3,4,5)
        B 修改了该条记录,改为(a,b,c,d,e)
        B 提交(commit)
        A 第二次读该记录,发现是(a,b,c,d,e)

重点看事务  A ,在同一个事务中先后读取同一条记录,但是两次读到的数据不一致
注意,B 执行了 commit。如果 B 没有执行 commit,那是脏读


幻读
        1. A 先读一条记录,发现没有该记录
        2. B 插入该记录,并提交
        3. A 尝试插入一条记录,发现插入不进去,存在该记录
        4. A 再次查询该记录,发现还是不存在

B 插入了该记录,并提交。那么 A 能查到该记录吗?
不能。如果 A 能查到该记录,那么 1 3 步骤查到的数据肯定不一样,这叫什么?这叫不可重复读。这点也是不可重复读和幻读的第 1 个区别

B 插入了该记录,并提交。那么 A 能插入该记录吗?
也不能。。。比如主键唯一,unique

幻读是针对 insert 插入语句,不可重复读针对 update 和 delete 语句。这是不可重复读和幻读的第 2 个区别

查询查不到,插入又显示已经存在。就像出现幻觉了一样


三、事务隔离级别

隔离级别脏读不可重复读幻读
read uncommitted111
read committed(oracle 默认)011
repeatable read(mysql 默认)001
serializable000

1 表示在该隔离级别下会出现该种问题,0反之
事务的隔离级别越低,并发能力越高,越容易出现问题

-- 查看事务隔离级别
select @@transaction_isolation;
-- 设置事务隔离级别
set session|global transaction isolation level xxx;	# xxx 为隔离级别
# global 对全局隔离级别生效,后面获取的连接都会生效
# session 仅对当前会话生效

read uncommitted (读未提交)。这种隔离级别会读到未提交的数据,会出现脏读问题
read committed(读已提交)。读已提交的数据,如果 B 在 A 事务过程中提交,A 会在一个事务中读一条记录,两次查询结果不同,会出现不可重复读问题
repeatable read(可重复读)。在一个事务 A 中,无论 B 是否提交改变,A 查询到的结果在事务 A 中都是相同的。但是如果 B 插入并提交,A 就无法插入。查询不存在,插入显示存在,会出现幻读问题
serializable(序列化)。如果 A 查询记录不存在,B 打算插入,B 会被阻塞。等 A 提交后 B 才会继续执行,避免幻读问题

四、sql 演示

4.1 脏读

  1. 先创建一张银行帐户表,往里面添加用户。左边为事务 A ,右边事务 B
    在这里插入图片描述
    在这里插入图片描述
  2. 设置两个事务,提交类型为手动提交,事务隔离级别为 read uncommitted,开启事务。以下操作在注释中,用1. 2. 3. 表示代码执行过程
    在这里插入图片描述
    事务 A 查询到了 事务 B 未提交的数据。张三并没有真的扣去1000元。该事务还没提交,可能 rollback 回滚了,对吧?

解决办法是,把事务的隔离级别设置为 read committed
在这里插入图片描述


4.2 不可重复读

read committed 下会出现不可重复读的问题
在这里插入图片描述
解决办法是,把事务的隔离级别设置为 repeatable read
在这里插入图片描述


4.3 幻读

repeatable read 下会出现幻读问题
在这里插入图片描述
== serializable== 解决幻读问题
在这里插入图片描述
由于 A 已经查询过记录,所以 当B尝试插入的时候,会被阻塞。等待 事务 A 提交后,B 才会继续执行。从而避免幻读的问题
注意,查询的是 id = 4,而不是姓名等于赵四。因为 id 是主键唯一,如果是赵四,无论 B 是否插入赵四,A都可以再插入一条名叫赵四的帐户,不会出现幻读


五、演示代码

事务a

CREATE DATABASE bank;
USE bank;
CREATE TABLE account (id INT PRIMARY KEY COMMENT 'id',name VARCHAR(20) COMMENT '姓名',money DECIMAL(12, 2) COMMENT '帐户余额'
) COMMENT '帐户表';
INSERT INTO account (id, name, money) values(1, '张三', 5000),(2, '李四', 3000),(3, '王五', 4000);
USE bank;
-- 事务 A
SET @@AUTOCOMMIT = 0;   # 设置手动提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ; # 事务隔离级别
START TRANSACTION ;     # 开启事务
# 1. A 先查询 account 表中,张三有多少钱
SELECT * FROM bank.account WHERE NAME = '张三' ;# 结果:1,张三,5000.00
# 3. A 再查 张三有多少钱
SELECT * FROM bank.account WHERE NAME = '张三' ;# 1,张三,4000.00
# 关闭事务
COMMIT;-- read committed 解决 脏读问题
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED ;# 1. A 先查询 account 表中,张三有多少钱
SELECT * FROM bank.account WHERE NAME = '张三' ;# 结果:1,张三,5000.00
# 3. A 再查 张三有多少钱
SELECT * FROM bank.account WHERE NAME = '张三' ;# 1,张三,5000.00,未读到 事务 B 中未提交的数据,无脏读问题
# 关闭事务
COMMIT;-- read committed 下出现不可重复读的问题
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED ;
# 1. A 先查询 account 表中,张三有多少钱
SELECT * FROM bank.account WHERE NAME = '张三' ;# 结果:1,张三,5000.00
# 4. A 再查 张三有多少钱
SELECT * FROM bank.account WHERE NAME = '张三' ;# 1,张三,4000.00,读到 事务 B 中已提交的数据,出现不可重复读的问题
# 关闭事务
COMMIT;-- repeatable read 解决不可重复读问题
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;
# 1. A 先查询 account 表中,张三有多少钱
SELECT * FROM bank.account WHERE NAME = '张三' ;# 结果:1,张三,5000.00
# 4. A 再查 张三有多少钱
SELECT * FROM bank.account WHERE NAME = '张三' ;# 1,张三,5000.00,未读到事务B中已提交的数据,未出现不可重复读的问题
# 关闭事务
COMMIT;-- repeatable read 出现幻读问题
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;START TRANSACTION ;
# 1. A 先查询用户 4 是否存在
SELECT * FROM account WHERE id = 4;# 查询结果为空
# 4. A 向表中添加用户4
INSERT INTO account (id, name, money) value(4, '赵四', 0);# 报错,已存在该用户
# [2023-06-24 20:33:06] [23000][1062]
# Duplicate entry '4' for key 'account.PRIMARY'
COMMIT ;-- serializable 解决幻读问题
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
START TRANSACTION ;
# 1. A 先查询 id 为 4 的用户是否存在
SELECT * FROM account WHERE id = 4;# 查询结果为空
# 4. A 向表中添加用户赵四, 添加成功
INSERT INTO account (id, name, money) value(4, '赵四', 0);
# 15 A 再次查询用户 赵四 是否存在
SELECT * FROM account WHERE id = 4;# 查询成功
COMMIT ;

事务b

USE bank;
-- 事务 B
SET @@AUTOCOMMIT = 0;   # 设置手动提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ; # 事务隔离级别
START TRANSACTION ;     # 开启事务
# 2. B 从张三帐户中扣去 1000 元,转移到李四的帐户
UPDATE bank.account SET money = money - 1000 WHERE NAME = '张三' ;
# 关闭事务,撤回扣钱操作
ROLLBACK;-- read committed 解决 脏读问题
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED ;START TRANSACTION ;     # 开启事务
# 2. B 从张三帐户中扣去 1000 元,转移到李四的帐户
UPDATE bank.account SET money = money - 1000 WHERE NAME = '张三' ;
# 关闭事务,撤回扣钱操作
ROLLBACK;-- read committed 下出现不可重复读的问题
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED ;
# 2. B 从张三帐户中扣去 1000 元,转移到李四的帐户
UPDATE bank.account SET money = money - 1000 WHERE NAME = '张三' ;
# 3. 提交事务,确认扣钱操作
COMMIT ;# 把张三的钱恢复到 5000
UPDATE account SET money = money + 1000 WHERE NAME = '张三';-- repeatable read 解决不可重复读问题
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;
# 2. B 从张三帐户中扣去 1000 元,转移到李四的帐户
UPDATE bank.account SET money = money - 1000 WHERE NAME = '张三' ;
# 3. 提交事务,确认扣钱操作
COMMIT ;-- repeatable read 出现幻读问题
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;START TRANSACTION ;
# 2. B 向表中添加用户 4
INSERT INTO account (id, name, money) value(4, '赵四', 0);
# 3. 提交
COMMIT;# 删除用户 4
DELETE FROM account WHERE id = 4;-- serializable 解决幻读问题
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
START TRANSACTION ;
# 2. B 向表中添加用户 4
INSERT INTO account (id, name, money) value(4, '赵四', 0);# 由于 A 查询过 用户4,B 被阻塞
# 3. 提交
COMMIT;

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPS数据清洗+R语言读取文件画频数分布直方图

R语言是一门好语言,但很多人在读取文件中数据时会遇到问题。比如我遇到的问题就是从文件中读取数据后,数据无法用于画图。 检索了N篇博文(抱歉我实在无法一一列举30篇博文)后,终于看到曙光,事实告诉我学任…

关于数据库SQL优化

简介 在项目上线初期,业务数据量相对较少,SQL的执行效率对程序运行效率的影响可能不太明显,因此开发和运维人员可能无法判断SQL对程序的运行效率有多大。但随着时间的积累,业务数据量的增多,SQL的执行效率对程序的运行…

Windows11添加用户自定义短语

比如要输入手机号码,直接输入sj就会弹出预先设定好的手机号,也可以预先设置好邮箱,身份证等等,这样就不用输入了 这个咋设置的有时候确实会忘记,所以就记下来了 步骤 第一步 打开设置 时间和语言>语言和区域 第二…

虹科分享 | 高考大数据可视化志愿填报分析-基于虹科Domo BI工具

高考是中国教育系统中一项极为重要的考试,它不仅是学生完成高中学业的重要标志,也是进入大学的门槛。每年高考都会吸引数百万学生参加,同时也吸引了各地高校和招生部门的关注。高考招生数据是教育研究和政策制定的重要依据,通过对…

【算法基础】快速排序(模板)

👦个人主页:Weraphael ✍🏻作者简介:目前正在学习c和算法 ✈️专栏:【C/C】算法 🐋 希望大家多多支持,咱一起进步!😁 如果文章有啥瑕疵 希望大佬指点一二 如果文章对你有…

Elasticsearch:倒数排序融合 - Reciprocal rank fusion

警告:此功能处于技术预览阶段,可能会在未来版本中更改或删除。 Elastic 将尽最大努力修复任何问题,但技术预览中的功能不受官方 GA 功能的支持 SLA 约束。 倒数排序融合(RRF)是一种将具有不同相关性指标的多个结果集组…

java.sql.Time 字段时区问题 Mybatis 源码分析

java.sql.Time 字段时区问题 系列文章目录 第一章 初步分析 第二章 Mybatis 源码分析 第三章 Jackson 源码分析 意想不到的Time处理类 文章目录 java.sql.Time 字段时区问题 系列文章目录前言Mybatis源码阅读1. ResultSetImpl部分源码:2. SqlTimeValueFactory部分…

【AUTOSAR】BMS开发实际项目讲解(二十九)----电池管理系统电池充放电功率控制与SOC

电池充放电功率控制 关联的系统需求 Sys_Req_3901、Sys_Req_3902、Sys_Req_3903、Sys_Req_3904; 功能实现描述 电池充放电功率控制主要包括以下内容: 60S可用功率 参见[CELL] 30S可用功率 参见[CELL] 10S可用功率 参见[CELL] SOP算法 ID Description ASI…

Nginx(3)nginx的Rewrite功能

nginx跨域 Rewrite功能配置Rewrite的相关命令Rewrite的案例域名跳转域名镜像独立域名目录自动添加/合并目录防盗链 Rewrite功能配置 Rewrite是Nginx服务器提供的一个重要基本功能,是Web服务器产品中几乎必备的功能。主要的作用是用来实现URL的重写。 注意:Nginx服…

【iVX】在百花齐放的低代码平台中独领风骚

💂作者简介: THUNDER王,一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学本科在读,同时任汉硕云(广东)科技有限公司ABAP开发顾问。在学习工作中,我通常使用偏后端的开发语言A…

openssl版本升级与降级

openssl版本升级与降级 flyfish 环境 Ubuntu 22.04 1.1.1升级3.1.1 查看openssl版本 openssl versionOpenSSL 1.1.1t 7 Feb 2023https://www.openssl.org/source/ 编译和安装 ./config --prefix/usr/local/openssl311 make -j8 make install进入/usr/local/openssl311/l…

Web服务器群集:Nginx+Tomcat实现负载均衡与动静分离集群

目录 一、理论 1.多实例 2.Nginx负载均衡 3.Nginx动静分离 4.配置NginxTomcat负载均衡 5.配置NginxTomcat动静分离集群 6.Nginx 四层代理配置 二、实验 1.配置NginxTomcat负载均衡 2.、配置NginxTomcat动静分离集群 三、问题 1.服务器群集与集群的区别 四、总结 一…