首页 > 数据库 >Mysql-事务的基本特性和隔离级别

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

时间:2024-05-07 14:11:18浏览次数:30  
标签:事务 窗口 隔离 查询 提交 Mysql 2.1 级别

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

标签:事务,窗口,隔离,查询,提交,Mysql,2.1,级别
From: https://www.cnblogs.com/yang37/p/18177105

相关文章

  • MySQL-基础语法教程
    基础解析:select要几列where要几行,用来对行进行过滤,加where,查出来的行变少*代表所有的列    增删改查 UPDATESET更新UPDATEscoresSETscore=300WHERENAME="王大"ANDkemu="语文"     delete语法DELETEFROMscoresWHEREID=11 #删除......
  • mysql索引使用基础
    1.创建&删除MySQL可以通过CREATE、ALTER、DDL三种方式创建一个索引。在MySQL中,使用CREATEINDEX语句可以创建索引。具体语法如下:CREATEINDEXindexNameONtableName(columnName(length)[ASC|DESC]);其中,indexName是索引的名称,tableName是要在其上创建索引的表名,column......
  • Linux非root用户安装mysql(5.7)
    1、下载安装包···········2、安装MySQL解压:tarxzvfmysql-5.7.31-linux-glibc2.12-x86_64.tar.gzmvmysql-5.7.31-linux-glibc2.12-x86_64mysql配置my.cnf文件:cat>>my.cnf<<EOF[mysqld]basedir=/app/mysqldatadir=/app/mysql/dataport=3333s......
  • mysql安装使用教程
    一、下载mysql安装包官网:https://dev.mysql.com/downloads/mysql/默认会跳转到最新版本的下载页面,也可以在旧版本集中选择需要安装的版本。MSIInstaller是安装程序,ZIPArchive是压缩包形式。安装程序会有图形界面引导安装,根据步骤进行选择即可。压缩包形式更方便快捷,解压后需......
  • MySQL夺命16问,你能坚持到第几问(转)
    原文:https://zhuanlan.zhihu.com/p/5344154091、数据库三大范式是什么?**第一范式:每个列都不可以再拆分。第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。在设计数据库结......
  • [转帖]【MySQL】字段名与关键字冲突解决办法
    https://www.jianshu.com/p/50e59feb3e83   首先,不推荐使用MySQL的关键词来作为字段名,但是有时候的确没有注意,或者因为之前就这么写了,没办法,那怎么办呢?方法1,改字段名,改了肯定就没问题了。这个就不细说了。方法2,使用引号`来处理。  下面就详细的说明一下怎样使用方法......
  • allure功能使用-区分测试用例重要级别severity
     编写测试用例时,需要区分测试用例的级别,在其方法前添加注解@allure.severity(allure.severity_level.NORMAL),allure.severity_level.NORMAL为重要级别,分别有以下分类:Trivial--不重要,轻微缺陷(必输项无提示或提示不规范)Minor--不太重要,次要缺陷(界面错误或与UI需求不符)Normal-......
  • 在Windows下用navicat,连接虚拟机的MySQL
    在Windows下用navicat,连接虚拟机的MySQL目录(一)防火墙1.查看防火墙状态2.关闭防火墙(二)登录MySQL1.登录2.查看MySQL端口号(三)连接navicat1.点击连接2.新建连接3.连接成功(四)修改虚拟机MySQL端口号1.打开配置文件2.修改端口号3.重启MySQL下面是报错原因总结:(下次有再补......
  • MySQL执行SQL文件的几种方式
    方式一:mysql-emysql-e"sourcebatch-file"1方式二:mysql<batch-filemysql-hhost-uuser-p<batch-file1对于这种方式,还可以查看文件执行时的输出,有如下两种方法:mysql<batch-file|moremysql<batch-file>mysql.out12方式三:mysql客户端命令行方式#先登录mysql客户......
  • Docker安装mysql
    dockerpullmysql:5.7:从DockerHub上拉取MySQL5.7的镜像。dockerimages:列出所有已下载的镜像,确认MySQL5.7是否已经成功下载。mkdir-p/home/service/mysql/data:创建一个用于存放MySQL数据的目录。mkdir-p/home/service/mysql/conf:创建一个用于存放MySQL配置文件的目录......