Mysql-事务的基本特性和隔离级别

news/2024/10/6 8:26:09

0.背景

在数据库中,事务是一组数据库操作,可以将事务操作视为一个基本的工作单元。

1.事务的基本特性

事务的基本特性“ACID”

对于事务呢,就是这一组sql操作,要确保ACID这4个基本特性。

哎,八股文不好背,我记忆方式是:一元吃个(原持隔)

  • 原子性(Atomicity):事务中的所有操作要么全部执行成功,要么全部失败回滚。如果一个操作失败,整个事务都会被回滚到初始状态,不会留下部分完成的结果。
  • 一致性(Consistency):事务执行前后,数据库的完整性约束保持一致。换句话说,事务执行后,数据库从一个一致的状态转换到另一个一致的状态。
  • 隔离性(Isolation):事务的执行结果对其他事务是隔离的,一个事务的执行不应该被其他事务所影响。事务之间应该相互独立,即使在并发执行的情况下也是如此。
  • 持久性(Durability):一旦事务提交成功,其所做的修改将永久保存在数据库中,并且不会因为系统故障而丢失。即使系统崩溃,数据库也能够在恢复后保持原有的状态。

2.事务的隔离级别

当涉及到多个事务并行执行时,就可能会涉及到多个事务操作相同的数据,这个时候就会出现一些问题。

2.1 可能的问题

先说事务处理时可能遇到的几种问题。

方便后方演示,建个表准备下。

-- 创建1张u_user表
CREATE TABLE `u_user`  (`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',`name` varchar(10) NOT NULL COMMENT '姓名',`age` int NOT NULL COMMENT '年龄',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`)
);-- 插入2条数据
INSERT INTO `u_user` (`name`, `age`) VALUES ('yang', 12);
INSERT INTO `u_user` (`name`, `age`) VALUES ('su', 13);-- 查询下
SELECT * from u_user;

image-20240506164530057

默认是自动提交的,使用下方命令查看。

SELECT @@autocommit;

image-20240506165029121

关闭自动提交,方可显式使用命令。

COMMIT; 提交事务

ROLLBACK;回滚事务

SET AUTOCOMMIT = 0;
SELECT @@autocommit;

image-20240506165056303


在 MySQL 中,每个连接都是独立的,因此在一个窗口中关闭了自动提交,在新开的窗口中并不会生效。

要在新窗口中也应用关闭自动提交的设置,你需要在新窗口中执行相同的 SQL 语句 SET AUTOCOMMIT = 0

image-20240506165712783


后方我们站在左侧窗口1(当前事务)的角度来看数据,假设窗口2(其他事务)的操作我们是不知情的。

然后我们就会在窗口1中查询到各种奇奇怪怪的数据。

image-20240506170032397

2.1.1 脏读

2.1.1.1 现象

脏读:读取到了其它事务中未提交的数据。

2.1.1.2 演示

窗口2将yang的年龄修改为20,尚未提交,在窗口1中查询,查到的数据是窗口2中这个尚未提交的数据20。

窗口1读取到了窗口2中没有提交的数据20。

image-20240506171808208

窗口1拿着未提交的脏数据20继续操作,然后窗口2回滚了?宏观来看,yang这个字段就没有存在过20这个值,似乎读取到了一个不存在的数据,一切都乱了。

2.1.2 不可重复读

假设我们解决了脏读问题,即不会读取到未提交的数据,这个时候还是会有问题。

2.1.2.1 现象

不可重复读:读取到了其他事务已经提交的数据,但前后读取的结果不同。

区分脏读,不可重复读运气好点,读到的是已经提交过的数据(也许这个事务时间比较长)。

2.1.2.2 演示

窗口2中先后将yang的年龄修改为20、30,也做了提交(不是脏读数据)。

但是在窗口1中查询时,前后查询出来了20、30这两个值。

就会疑惑,咋查了2次值还不一样呢?即窗口1中多次查询年龄数据,前后查询的结果不一致。

首次查询得到年龄值是20。

image-20240506173126761

又查了下,年龄咋变成30了。

image-20240506173201067

窗口1查询,每次查出来的结果还不一样了,太不靠谱了。

2.1.3 幻读

2.1.3.1 定义

幻读是指一次事务中前后数据量发生变化

区分不可重复读,不可重复读是在单条或者多条数据的角度来看待数据,这种可以通过行锁之类的操作来解决。

幻读是在表整体角度来看待数据,这个时候整体数据量发生变化,仅仅通过行锁已经无法解决了。

2.1.3.2 演示

窗口2中先插入了一条数据,此时在窗口1中查询总条数为3(由2增加到3)。

然后窗口2中又再次插入了一条数据,窗口1查询总条数为4。

窗口1就很奇怪,这个数据量咋变来变去。

首次查询条数,是3。

image-20240506174204160

再次查询,条数又变成了4。

image-20240506174234298

2.2 事务隔离级别

通过设置事务的隔离级别,来解决对应的问题。

隔离性从低到高,并发性从高到低。

嗯,为了保持更强的隔离性,需要付出的措施就更多,并发能力当然有所降低咯。

隔离级别 脏读(是否存在) 不可重复读(是否存在) 幻读(是否存在)
RU Read uncommitted(读未提交)
RC Read committed(读已提交) ×
RR Repeatable read(可重复读)默认的隔离级别 × ×
Serializable(可串行化) × × ×

2.2.1 Read uncommitted(RU读未提交)

该隔离级别的事务可以看到其他事务中未提交的数据。

该隔离级别因为可以读取到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此我们把该级别读取到的数据称之为脏数据,把这个问题称之为脏读。

-- 将当前会话(session)的事务隔离级别设置为读未提交。
-- 这个设置仅对当前会话有效,对其他会话不会产生影响。
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

2.2.2 Read committed(RC读已提交)

该隔离级别的事务能读取到已经提交事务的数据,因此它不会有脏读问题。

但由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同 SQL 查询中,可能会得到不同的结果,这种现象叫做不可重复读。

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

2.2.3 Repeatable read(RR可重复读)

MySQL 的默认事务隔离级别,它能确保同一事务多次查询的结果一致。

但也会有新的问题,比如此级别的事务正在执行时,另一个事务成功的插入了某条数据,但因为它每次查询的结果都是一样的,所以会导致查询不到这条数据,自己重复插入时又失败(因为唯一约束的原因)。

明明在事务中查询不到这条信息,但自己就是插入不进去,这就叫幻读 (Phantom Read)。

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

2.2.4 Serializable(可串行化)

事务最高隔离级别,它会强制事务排序,使之不会发生冲突,从而解决了脏读、不可重复读和幻读问题,但因为执行效率低,所以真正使用的场景并不多。

SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

2.3 扩展

2.3.1 查询事务的隔离级别

select @@transaction_isolation;

image-20240506160753174

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

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

相关文章

使用pycnblog一键拖拽同步markdown和图片

目录原因解决办法参考链接准备工作配置config.yaml其他设置图片运行 原因本地使用Typora写完文档,上传博客园时,图片不能同步解决办法 参考链接博客园上传markdown文件准备工作下载工具pycnblog安装Python3pip install pyyaml配置config.yaml blog_url: https://rpc.cnblogs.…

blazor优雅的方式导入组件相关的js脚本

基本的组件导入方式为:1 await JsRuntime.InvokeVoidAsync("import", $"XXXXX.js");优雅的组件导入方式:1 await JsRuntime.ImportAsync<DocEditor>();这种优雅一点不难,只需要写一个扩展方法,把他放在任意地方并且导入命名空间,或者放到和项目…

02 冒泡排序

02 冒泡排序1.冒泡排序的含义每次交换两个,把大的扔在末尾, 每一轮可以确定末尾是最大的,然后是次尾部,依次进行下去。 老师:每次都是搞定最大的数,最大的数往右边冒。再接着搞定下一轮,直到整个数组有序。 图示:2.示例代码 def bubble_sort(arr):# if not arr or len(…

一站式生活新体验:可视化技术让公寓商场综合楼焕新生

可视化技术将传统的居住与购物空间进行了完美融合。在这里,你不再需要为了购买生活用品而特地跑到远处的商场,也不再需要为了找一家心仪的餐厅而四处奔波。通过可视化技术,你可以轻松查看到楼内的各个商铺、餐厅、健身房等配套设施的分布情况,一键导航直达目的地,享受一站…

MySQL-基础语法教程及事务和索引

基础解析: select 要几列 where要几行,用来对行进行过滤,加where,查出来的行变少 *代表所有的列 增删改查UPDATE SET 更新 UPDATE scores SET score=300 WHERE NAME="王大" AND kemu="语文" delete语法 DELETE FROM scores WHERE ID =11#删除整张表里的…

MySQL-基础语法教程

基础解析: select 要几列 where要几行,用来对行进行过滤,加where,查出来的行变少 *代表所有的列 增删改查UPDATE SET 更新 UPDATE scores SET score=300 WHERE NAME="王大" AND kemu="语文" delete语法 DELETE FROM scores WHERE ID =11#删除整张表里的…

WinForm下实现子窗体

如果想要实现在同一个Form下的子窗体切换,下面的方法可以实现。窗体设计,如图增加子窗体。鼠标右键项目,选择添加,选择用户控件注意修改用户控件的大小尺寸,和GroupBox的尺寸匹配。建立好子窗体后,在主Form里面先声明各个子窗体类,如下://定义用户窗口变量public windo…

c# 多线程的几种方式 【转载】

1.什么是线程? 进程作为操作系统执行程序的基本单位,拥有应用程序的资源,进程包含线程,进程的资源被线程共享,线程不拥有资源。2.前台线程和后台线程的区别? 程序关闭时,后台线程直接关闭,但前台线程会执行完后关闭。 通过Thread类新建线程默认为前台线程。其他方式创建…