目  录

一、概述

二、ACID 四大特性

三、MySQL 事务

 四、事务隔离级别

1.说明

2.现象

(1)脏读

(2)不可重复读

(3)幻读

3.查看隔离级别

4.设置隔离级别

5.隔离级别

(1)初始化

(2)读未提交

(3)读提交

(4)可重复读

(5)串行化

6.可重复读的幻读

(1)说明

(2)快照读解决幻读

(3)当前读解决幻读

(4)出现幻读的两种情况


一、概述

  1. 事务是一个最小的工作单元。数据库中,事务表示一个完整的行为;
  2. 事务只针对 DML 语句
  3. 使用事务机制后,在同一个事务当中,多条 DML 语句或同时执行成功,或同时执行失败;
  4. 事务的经典实例:账户转账,或一方金额减少和一方金额增加同时成功,或同时失败。

二、ACID 四大特性

  1. 原子性(Atomicity):事务包含的所有操作或全部成功,或全部失败;
  2. 一致性(Consistency):事务开始前和完成后,数据应该是一致的;
  3. 隔离性(Isolation):多个用户并发访问数据库时,数据库为每一个用户开启的事务不能被其他事务的操作所干扰,多个并发事务之间要相互隔离;
  4. 持久性(Durability):一个事务一旦被提交,则对数据库中的数据改变是永久的,即便是数据库系统出现故障也不会丢失提交事务的操作。

三、MySQL 事务

  1. 开启 MySQL 事务:【start transaction;】或【begin;】;
  2. 回滚事务:【rollback;】;
  3. 提交事务:【commit;】;
  4. 只要执行 rollback 或 commit,事务都会结束;
  5. MySQL 默认事务自动提交,执行一条 DML 语句提交一次。

 四、事务隔离级别

1.说明

隔离级别现  象
脏读不可重复读幻读

读未提交

(read uncommitted)

存在存在存在

读提交

(read committed)

不存在存在存在

可重复读

(repeatable read)

不存在不存在存在

串行化

(serializable)

不存在不存在不存在
  1. 隔离级别排序:读未提交 < 读提交 < 可重复读 < 串行化
  2. 不同隔离级别会存在不同现象,按照严重性排序:脏读 > 不可重复读 > 幻读
  3. Oracle 默认隔离级别是读提交,MySQL 默认隔离级别是可重复读。

2.现象

(1)脏读

        一个事务读取了另一个事务尚未提交的数据。此时如果另一个事务回滚或修改了数据,那么读取脏数据的事务就会出现数据处理错误。


(2)不可重复读

        一个事务内,多次读取同一条数据,得到的结果可能不一致。因为其他事务可能对该数据做出修改操作。


(3)幻读

        事务执行过程中,前后几次相同查询条件得到的结果集不一致,可能更多也可能更少。


3.查看隔离级别

  1. 查看当前会话的隔离级别:【select @@transaction_isolation;】;
  2. 查看全局的隔离级别:【select @@global.transaction_isolation;】。
select @@global.transaction_isolation;select @@transaction_isolation;


4.设置隔离级别

  1. 设置当前会话的隔离级别:【set session transaction isolation level <隔离级别>】;
  2. 设置全局的隔离级别:【set global transaction isolation level <隔离级别>】。
# 设置全局隔离级别-- 读未提交
set global transaction isolation leve read uncommitted;-- 读提交
set global transaction isolation level read committed;-- 可重复读
set global transaction isolation level repeatable read;-- 串行化
set global transaction isolation level serializable;# 设置会话隔离级别-- 读未提交
set session transaction isolation leve read uncommitted;-- 读提交
set session transaction isolation level read committed;-- 可重复读
set session transaction isolation level repeatable read;-- 串行化
set session transaction isolation level serializable;


5.隔离级别

(1)初始化

        事先准备好一个 users 表,表中有 id,name,gender 字段。

drop table if exists users;create table users(id int primary key auto_increment,name varchar(10),gender varchar(2) default '未知'
);insert into users(name, gender) values('黄梓婷', '女'),('赵聪', '男'),('吕不韦', '男');select * from users;


(2)读未提交

  1. A 事务与 B 事务,A 事务可以读到 B 事务未提交的数据
  2. 这种级别的两个事务之间几乎没有隔离,实际数据库产品中,没有默认该隔离级别的;
  3. 但前隔离级别,脏读、不可重复读、幻读 现象都存在
  4. 模拟实例:先将全局事务隔离级别设置为 read uncommitted。然后开启两个 dos 命令窗口分别登录 MySQL 来模拟 A、B事务。
-- 1.设置全局隔离级别
set global transaction isolation level read uncommitted;-- 2.然后打开两个 dos 命令窗口,分别登录 MySQL
A 事务B 事务
3. mysql> use test;
4. mysql> use test;
5. mysql> start transaction;
6. mysql> start transaction;
7. mysql> select * from users;
8. mysql> insert into users(name, gender) values('陈子悦', '女');
9. mysql> select * from users;

         可以看到,出现了脏读,意味着三个现象都会出现。


(3)读提交

  1. A 事务与 B 事务,A 事务可以读取到 B 事务提交之后的数据
  2. Oracle 默认是此隔离级别;
  3. 当前隔离级别,会出现不可重复读和幻读现象
  4. 模拟实例:先将全局事务隔离级别设置为 read committed。然后开启两个 dos 命令窗口分别登录 MySQL 来模拟 A、B事务。
-- 1.设置全局隔离级别
set global transaction isolation level read committed;-- 2.然后打开两个 dos 命令窗口,分别登录 MySQL
A 事务B 事务
3. mysql> use test;
4. mysql> use test;
5. mysql> start transaction;
6. mysql> start transaction;
7. mysql> select * from users;
8. mysql> insert into users(name, gender) values('陈子悦', '女');
9. mysql> select * from users;
9. mysql> commit;
10. mysql> select * from users;
11. mysql> update users set name = '牛佳佳' where id = 2;
12. mysql> select * from users;

        可以看到,出现了不可重复读和幻读。 


(4)可重复读

  1. A 事务与 B 事务,A 事务开启后读取记录,B 事务修改数据并提交,A 事务读取到的还是修改前的记录;
  2. MySQL 默认是此隔离级别;
  3. 模拟实例:先将全局事务隔离级别设置为 repeatable read。然后开启两个 dos 命令窗口分别登录 MySQL 来模拟 A、B事务。
-- 1.设置全局隔离级别
set global transaction isolation level repeatable read;-- 2.然后打开两个 dos 命令窗口,分别登录 MySQL
A 事务B 事务
3. mysql> use test;
4. mysql> use test;
5. mysql> start transaction;
6. mysql> start transaction;
7. mysql> select * from users;
8. mysql> update users set name = '艾东东' where id = 2;
9. mysql> select * from users;
10. mysql> commit;
11. mysql> select * from users;
12. mysql> insert into users(name, gender) values('张弘毅', '男');
13. mysql> commit;
14. mysql> select * from users;
15. select * from users for update;

# A 事务
mysql> use test;
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)mysql> select * from users;
+----+--------+--------+
| id | name   | gender |
+----+--------+--------+
|  1 | 黄梓婷 | 女     |
|  2 | 牛佳佳 | 男     |
|  3 | 吕不韦 | 男     |
|  5 | 陈子悦 | 女     |
+----+--------+--------+
4 rows in set (0.00 sec)mysql> select * from users;
+----+--------+--------+
| id | name   | gender |
+----+--------+--------+
|  1 | 黄梓婷 | 女     |
|  2 | 牛佳佳 | 男     |
|  3 | 吕不韦 | 男     |
|  5 | 陈子悦 | 女     |
+----+--------+--------+
4 rows in set (0.00 sec)mysql> select * from users;
+----+--------+--------+
| id | name   | gender |
+----+--------+--------+
|  1 | 黄梓婷 | 女     |
|  2 | 牛佳佳 | 男     |
|  3 | 吕不韦 | 男     |
|  5 | 陈子悦 | 女     |
+----+--------+--------+
4 rows in set (0.00 sec)mysql> select * from users;
+----+--------+--------+
| id | name   | gender |
+----+--------+--------+
|  1 | 黄梓婷 | 女     |
|  2 | 牛佳佳 | 男     |
|  3 | 吕不韦 | 男     |
|  5 | 陈子悦 | 女     |
+----+--------+--------+
4 rows in set (0.00 sec)mysql> select * from users for update;
+----+--------+--------+
| id | name   | gender |
+----+--------+--------+
|  1 | 黄梓婷 | 女     |
|  2 | 艾东东 | 男     |
|  3 | 吕不韦 | 男     |
|  5 | 陈子悦 | 女     |
|  6 | 张弘毅 | 男     |
+----+--------+--------+
5 rows in set (0.00 sec)
# B 事务
mysql> use test;
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)mysql> update users set name = '艾东东' where id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> commit;
Query OK, 0 rows affected (0.00 sec)mysql> insert into users(name, gender) values('张弘毅', '男');
Query OK, 1 row affected (0.02 sec)mysql> commit;
Query OK, 0 rows affected (0.00 sec)

        可以看到 A 事务在使用【select * from users for update;】语句查询时会出现幻读,但是不加【for update】不会出现幻读。也就是说,幻读是可能会出现的,for update 是当前读。


(5)串行化

  1. 此隔离级别,避免了所有的问题
  2. 但是效率低,因为这种隔离级别会导致事务排队处理,不支持并发;
  3. 模拟实例:先将全局事务隔离级别设置为 serializable。然后开启两个 dos 命令窗口分别登录 MySQL 来模拟 A、B事务。
-- 1.设置全局隔离级别
set global transaction isolation level serializable;-- 2.然后打开两个 dos 命令窗口,分别登录 MySQL
A 事务B 事务
3. mysql> use test;
4. mysql> use test;
5. mysql> start transaction;
6. mysql> start transaction;
7. mysql> select * from users;
8. mysql> insert into users(name, gender) values('周子恩', '女');
9. commit;

        在 B 事务执行完 insert 语句后,会等待 A 事务结束,否则 B 事务不会进入下一步。两个事务是串行执行的。 


6.可重复读的幻读

(1)说明

  1. MySQL 默认隔离级别是可重复读,但是不可以完全避免幻读问题;
  2. 解决幻读的方法:
    1. 快照读:普通 select 语句都是快照读。通过 MVCC(多版本并发控制) 方式解决幻读,因为在可重复的隔离级别中,事务执行的查询数据与该事务启动时查询的数据是一致的,即使中间有新插入的数据,也不会被查询出来,所以避免了幻读问题;
    2. 当前读:带有 for update 的 select 语句、insert 语句、alert 语句、delete 语句都是当前读。通过 next-key lock(记录锁 + 间隙锁)的方式解决幻读,因为执行 select …… for update 语句时,会加上 next-key lock。若其他事务在 next-key lock 锁范围内插入了一条记录,则该语句会被阻塞,无法成功插入,所以也避免了幻读问题。

(2)快照读解决幻读

  1. 在整个事务处理过程中,执行相同的普通 select 语句,都是读取快照;
  2. 快照是固定某个时刻的数据;
  3. 原理:底层由 MVCC 实现,开始事务后,执行第一个查询语句后,会创建一个 read view,后续的查询语句利用该 read view,通过该 read view 可以在 undo log 版本链中找到事务开始时的数据,所以事务过程中每次查询到的数据是一致的。

(3)当前读解决幻读

  1. 每一次都读取最新数据;
  2. 事务开始,会对查询范围内的数据加锁,不允许其他事务对该范围内的数据进行增、删、改。即该 select 语句范围内的数据不允许并发,只能排队执行。next-key lock,就是 间隙锁 + 记录锁,间隙锁用来保证锁定范围内不允许执行 insert 操作,记录锁保证锁定范围不允许执行 update 和 delete 操作。

(4)出现幻读的两种情况

  1.  A 事务与 B 事务,在 A 事务中第一次查询使用快照读B 事务插入数据。然后在 A 事务中第二次查询使用当前读,则会产生幻读现象;

  2. A 事务与 B 事务,在 A 事务中第一次查询使用快照读,在 B 事务中插入数据。然后在 A 事务中更新 B 事务插入的那条记录。最后在 A 事务中再次使用快照读,则会产生幻读现象。(因为执行 update 操作,会在底层执行一次当前读)。

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

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

相关文章

Hutool中的Pair类详解

1. Pair类概述 Hutool工具库中的Pair类是一个简单的键值对数据结构&#xff0c;用于存储两个相关联的对象。它类似于Map的Entry&#xff0c;但更加轻量级&#xff0c;适用于需要临时存储两个相关联数据的场景。 2. Pair类的主要特点 简单轻量&#xff1a;不依赖复杂的数据结…

02-GBase 8s 事务型数据库 客户端工具dbaccess

dbaccess概述 数据库产品通常会提供一个命令行客户端工具。 数据库厂商 命令行客户端 Oracle sqlplus MySQL mysql Marladb mysql GBase 8s dbaccess Kingbase ES ksql DM8 disql dbaccess 是 GBase 8s 数…

手撕基于AMQP协议的简易消息队列-8(单元测试的编写)

在MQTest中编写模块的单元测试 在MQTest中编写makefile文件来编译客户端模块 all:Test_FileHelper Test_Exchange Test_Queue Test_Binding Test_Message Test_VirtualHost Test_Route Test_Consumer Test_Channel Test_Connection Test_VirtualHost:Test_VirtualHost.cpp ..…

Spark 之 metrics

peak memory.//sql/core/src/main/scala/org/apache/spark/sql/execution/aggregate/HashAggregateExec.scala: “peakMemory” -> SQLMetrics.createSizeMetric(sparkContext, “peak memory”), .//sql/core/src/main/scala/org/apache/spark/sql/execution/SortExec.scal…

HTTP/HTTPS协议(请求响应模型、状态码)

目录 HTTP/HTTPS协议简介 HTTP协议 HTTPS协议 请求 - 响应模型 HTTP请求 &#xff08;二&#xff09;HTTP响应 HTTPS协议与HTTP协议在请求 - 响应模型中的区别 HTTP/HTTPS协议简介 HTTP协议 定义 HTTP&#xff08;HyperText Transfer Protocol&#xff09;即超文本传输…

OpenHarmony 5.0 切换已连接过的wifi切换失败

目录 1.背景 2.流程分析 3.方案 1.背景 在OpenHarmony 5.0的设置中,输入密码进行wifi连接可以正常连接,然后多个已经连接过的wifi进行切换发现大概率切换失败 2.流程分析 wifi连接过程其实是先进行断开当前的wifi连接,然后再连接另一个wifi,如下: 虽然上述流程看起来没…

【Ollama】docker离线部署Ollama+deepseek

因为要做项目&#xff0c;实验室的服务器不联网&#xff0c;所以只能先打包一个基础的docker环境&#xff0c;然后再在实验室的服务器上进行解压和配置环境 参考&#xff1a;https://zhuanlan.zhihu.com/p/23377266873 1.打包基础的docker环境 这里最好用有cuda的&#xff0c…

如何使用极狐GitLab 软件包仓库功能托管 terraform?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;关于中文参考文档和资料有&#xff1a; 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 Terraform 模块库 (BASIC ALL) 基础设施仓库和 Terraform 模块仓库合并到单个 Terraform 模块仓库功能引入于极狐GitLab 15.1…

【QT】深入理解 Qt 中的对象树:机制、用途与最佳实践

深入理解 Qt 中的对象树&#xff1a;机制、用途与最佳实践 在使用 Qt 编程时&#xff0c;你是否注意到很多对象可以设置“父对象”&#xff1f;比如&#xff1a; QPushButton* btn new QPushButton(parentWidget);这不是简单的层级结构&#xff0c;而是 Qt 强大而优雅的 对象…

比较入站和出站防火墙规则

组织需要仔细配置防火墙规则&#xff0c;监控网络的传入和传出流量&#xff0c;从而最大限度降低遭受攻击的风险。在有效管理入站和出站防火墙规则前&#xff0c;了解入站与出站流量的区别至关重要。 一、什么是入站流量&#xff1f; 入站流量指的是并非源自网络内部&#xf…

Unity-Shader详解-其五

关于Unity的Shader部分的基础知识其实已经讲解得差不多了&#xff0c;今天我们来一些实例分享&#xff1a; 溶解 效果如下&#xff1a; 代码如下&#xff1a; Shader "Chapter8/chapter8_1" {Properties{// 定义属性[NoScaleOffset]_Albedo("Albedo", 2…

COLT_CMDB_linux_userInfo_20250508.sh修复历史脚本输出指标信息中userName与输出信息不一致问题

#!/bin/bash #IT_BEGIN #IT_TYPE3 #IT SYSTEM_LINUX_AGENTUSERDISCOVER|discovery.user[disc] #原型指标 #IT_RULE SYSTEM_LINUX_AGENTUSERGROUPID|groupId[{#USERNAME}] #IT_RULE SYSTEM_LINUX_AGENTUSERHOME|userHome[{#USERNAME}] #IT_RULE SYSTEM_LINUX_AGENTUSERNAME|user…

TCP 与 UDP报文

** TCP 与 UDP报文** 1. 引言 在网络通信中&#xff0c;TCP&#xff08;传输控制协议&#xff09; 和 UDP&#xff08;用户数据报协议&#xff09; 是两种最核心的传输层协议。它们各自适用于不同的场景&#xff0c;理解其工作原理对开发高性能网络应用至关重要。本文将详细解…

LabVIEW燃气轮机测控系统

在能源需求不断增长以及生态环境保护备受重视的背景下&#xff0c;微型燃气轮机凭借其在经济性、可靠性、维护性及排放性等方面的显著优势&#xff0c;在航空航天、分布式发电等众多领域得到广泛应用。随着计算机技术的快速发展&#xff0c;虚拟仪器应运而生&#xff0c;LabVIE…

基于vueflow可拖拽元素的示例(基于官网示例的单文件示例)

效果图 代码 <template><div style"width: 100%;height: calc(100vh - 84px)"><VueFlow :nodes"nodes" :edges"edges" drop"onDrop" dragover"onDragOver" dragleave"onDragLeave"><div cl…

笔试专题(十六)

文章目录 相差不超过k的最多数题解代码 最长公共子序列&#xff08;一&#xff09;题解代码 小红的口罩题解代码 春游题解代码 相差不超过k的最多数 题目链接 题解 1. 排序 滑动窗口 2. 为什么使用滑动窗口&#xff1f; 因为max-min < k&#xff0c;求这个区间内的数最…

技术视界 | 青龙机器人训练地形详解(三):复杂地形精讲之台阶

在前两篇中&#xff0c;我们依次讲解了“如何创建一个地形”以及“如何将地形添加到训练环境中”。从基础出发&#xff0c;逐步构建机器人可交互的三维仿真环境。在机器人强化学习训练中&#xff0c;地形的复杂度决定了策略的泛化能力&#xff0c;仅靠 jump_plat 和 jump_pit 等…

MYSQL之索引结构,为何要用B+树

索引的目的就是为了提高查询效率 索引的结构是B树&#xff0c;那么说到B树&#xff0c;必须提一下其他三种结构&#xff0c;分别是&#xff1a;二叉查找树、平衡二叉树、B树 我们来看看各自的结构特征 二叉查找树 特点:任何节点的左子节点的值都小于当前节点的值&#xff0c;右…

3.2.3 掌握RDD转换算子 - 2. 过滤算子 - filter()

在本节课中&#xff0c;我们深入学习了Spark RDD的过滤算子filter()。filter()算子能够通过指定的函数对RDD中的元素进行筛选&#xff0c;返回一个满足条件的新RDD&#xff0c;通常新RDD的元素个数会比源RDD少。通过案例演示&#xff0c;我们掌握了如何使用filter()来过滤列表中…

vue3使用轮播图组件swiper

一、在swiper的官网源码下载地址 下载Swiper - Swiper中文网 二、官网浏览轮播图类型地址 Swiper演示 - Swiper中文网 三、swiper配置参数地址 中文api - Swiper中文网 四、在vue3项目引入swiper npm install swiper 五、在vue3中使用 官网vue3中使用&#xff1a;Swiper…