从0开始回顾MySQL---事务四大特性

事务概述

  1. 事务是一个最小的工作单元。在数据库当中,事务表示一件完整的事儿。
  2. 一个业务的完成可能需要多条DML语句共同配合才能完成,例如转账业务,需要执行两条DML语句,先更新张三账户的余额,再更新李四账户的余额,为了保证转账业务不出现问题,就必须保证要么同时成功,要么同时失败,怎么保证同时成功或者同时失败呢?就需要使用事务机制。
  3. 也就是说用了事务机制之后,在同一个事务当中,多条DML语句会同时成功,或者同时失败,不会出现一部分成功,一部分失败的现象。
  4. 事务只针对DML语句有效:因为只有这三个语句是改变表中数据的。
    1. insert
    2. delete
    3. update

事务四大特性:ACID

  1. 原子性(Atomicity):是指事务包含的所有操作要么全部成功,要么同时失败。
  2. 一致性(Consistency):是指事务开始前,和事务完成后,数据应该是一致的。例如张三和李四的钱加起来是5000,中间不管进行过多少次的转账操作(update),总量5000是不会变的。这就是事务的一致性。
  3. 隔离性(Isolation):隔离性是当多个⽤户并发访问数据库时,⽐如操作同⼀张表时,数据库为每⼀个⽤户开启的事务,不能被其他事务的操作所⼲扰,多个并发事务之间要相互隔离。
  4. 持久性(Durability):持久性是指⼀个事务⼀旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

演示MySQL事务

在dos命令窗口中开启MySQL事务:start transaction; 或者:begin;
回滚事务:rollback;
提交事务:commit;
只要执行以上的rollback或者commit,事务都会结束。
MySQL默认情况下采用的事务机制是:自动提交。所谓自动提交就是只要执行一条DML语句则提交一次。

事务隔离级别

image.png
隔离级别从低到高排序:读未提交 < 读提交 < 可重复读 < 串行化
不同隔离级别会存在不同的现象,现象按照严重性从高到低排序:脏读 > 不可重复读 > 幻读

查看与设置隔离级别

mysql默认的隔离级别:可重复读(REPEATABLE READ)。

  • 查看当前会话的隔离级别:select @@transaction_isolation;
  • 查看全局的隔离级别:select @@gobal.transaction_isolation;

设置事务隔离级别:

  • 会话级:set session transaction isolation level read committed;
  • 全局级:set global transaction isolation level read committed;

不同现象

脏读

指的是一个事务读取了另一个事务尚未提交的数据,即读取了另一个事务中的脏数据(Dirty Data)。在此情况下,如果另一个事务回滚了或者修改了这些数据,那么读取这些脏数据的事务所处理的数据就是不准确的。

不可重复读

指在一个事务内,多次读取同一个数据行,得到的结果可能是不一样的。这是由于其他事务对数据行做出了修改操作,导致数据的不一致性。

幻读

指在事务执行过程中,前后两次相同的查询条件得到的结果集不一致,可能会变多或变少。

隔离级别

读未提交(READ UNCOMMITTED)

A事务与B事务,A事务可以读取到B事务未提交的数据。这是最低的隔离级别。几乎两个事务之间没有隔离。这种隔离级别是一种理论层面的,在实际的数据库产品中,没有从这个级别起步的。
当事务隔离级别是读未提交时,三种现象都存在:脏读,不可重复读,幻读。
我们可以开启两个DOS命令窗口,模拟两个事务,演示一下这种隔离级别。三种现象中最严重的是脏读,我们只需要演示脏读问题即可,因为存在脏读的话,就一定存在不可重复读和幻读问题。

将全局事务隔离级别设置为:READ UNCOMMITTED

set global transaction isolation level read uncommitted;

开启两个DOS命令窗口来模拟两个事务:A事务与B事务。

A事务B事务
mysql> use powernode
mysql> use powernode
mysql> start transaction;
mysql> start transaction;
mysql> select * from a;
image.png
mysql> insert into a values(4);
mysql> select * from a;
image.png

通过以上测试,可以看到,A事务读取到了B事务还没有提交的数据。这种现象就是脏读。

读提交(READ COMMITTED)

A事务与B事务,A事务可以读取到B事务提交之后的数据。Oracle数据库默认的就是这种隔离级别。

将数据库的全局事务隔离级别设置为读提交:READ COMMITTED

set global transaction isolation level read committed;

演示:

A事务B事务
mysql> use powernode
mysql> use powernode
mysql> start transaction;
mysql> start transaction;
mysql> select * from a;
image.png
mysql> insert into a values(4);
mysql> select * from a;
image.png
mysql> commit;
mysql> select * from a;
image.png

通过以上测试看出,A事务只能读取到B事务提交之后的数据。这种隔离级别解决了脏读问题,但肯定是存在不可重复读和幻读问题。因为只要事务B进行了增删改操作之后并提交了,事务A读取到的数据肯定是不同的。即:不可重复读和幻读都存在。

可重复读(REPEATABLE READ)

这个隔离级别是MySQL数据库默认的。
A事务和B事务,A事务开启后,读取了某一条记录,然后B事务对这条记录进行修改并提交,A事务读取到的还是修改前的数据。这种隔离级别称为可重复读。

将数据库全局隔离级别修改为可重复读:

set global transaction isolation level repeatable read;

演示:

A事务B事务
mysql> use powernode
mysql> use powernode
mysql> start transaction;
mysql> start transaction;
mysql> select empno,ename,sal from emp where empno=7369;
image.png
mysql> update emp set ename=‘SMITH’,sal=8000 where empno=7369;
mysql> commit;
mysql> select empno,ename,sal from emp where empno=7369;
image.png

通过以上测试得知:当事务隔离级别设置为可重复读时,避免了不可重复读问题。

那么在MySQL当中,当事务隔离级别设置为可重复读时,能够避免幻读问题吗?测试一下:

事务A事务B
mysql> use powernode
mysql> use powernode
mysql> start transaction;
mysql> start transaction;
mysql> select * from a;
image.png
mysql> insert into a values(5);
mysql> commit;
mysql> select * from a;
image.png

通过以上测试得知:**当事务隔离级别设置为可重复读时,也避免了幻读问题。是完全避免了幻读问题吗?并不是。**请看以下测试:

事务A事务B
mysql> use powernode
mysql> use powernode
mysql> start transaction;
mysql> start transaction;
mysql> select * from a;
image.png
mysql> insert into a values(6);
mysql> commit;
mysql> select * from a for update;
image.png

通过以上测试得知:当事务隔离级别设置为可重复读,MySQL会尽最大努力避免幻读问题,但这种隔离级别无法完全避免幻读问题。

串行化(SERIALIZABLE)

这种隔离级别最高,避免了所有的问题,缺点是效率低,因为这种隔离级别会导致事务排队处理,不支持并发。

设置数据库全局隔离级别为串行化:

set global transaction isolation level serializable;

演示:

事务A事务B
mysql> use powernode
mysql> use powernode
mysql> start transaction;
mysql> start transaction;
mysql> select * from a;
image.png
mysql> insert into a values(7);
mysql> select * from a;
image.png
mysql> commit;
image.png

通过以上测试得知:当事务隔离级别设置为串行化时,事务只能排队执行,不支持并发。

可重复读的幻读问题

在上面讲解过程中我提到,MySQL默认的隔离级别可重复读,在很大程度上避免了幻读问题(并不能完全解决),那么它是如何解决幻读问题的呢,解决方案包括两种:

  • 针对快照读(普通 select 语句),是通过 MVCC 方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好的避免了幻读问题。
  • 针对当前读(select … for update 等语句),是通过 next-key lock(记录锁+间隙锁)方式解决了幻读,因为当执行 select … for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好的避免了幻读问题。

快照读是如何解决幻读的

什么是快照读?普通的select语句都是采用的快照读。顾名思义:在整个事务的处理过程中,执行相同的一个select语句时,每次都是读取的快照。(快照指的是固定的某个时刻的数据,就像现实世界中的拍照一样,把那个美好的时刻留下来)。也就是说,当事务隔离级别是可重复读,并且执行的select语句是一个普通的select语句时,都会采用快照读的方式读取数据,底层实现原理是:

  • 底层由 MVCC(多版本并发控制)实现,实现的方式是开始事务后,在执行第一个查询语句后,会创建一个 Read View,后续的查询语句利用这个 Read View,通过这个 Read View 就可以在 undo log 版本链找到事务开始时的数据,所以事务过程中每次查询的数据都是一样的,即使中途有其他事务插入了新纪录,是查询不出来这条数据的,所以就很好的避免了幻读问题。

演示:

事务A事务B
mysql> use powernode
mysql> use powernode
mysql> start transaction;
mysql> start transaction;
mysql> select * from a; //快照读
image.png
mysql> insert into a values(5);
mysql> commit;
mysql> select * from a; //快照读
image.png

当前读是如何解决幻读的

当前读,顾名思义:每一次都读取最新的数据。当前读包括:update、delete、insert、select…for update。这个很好理解,因为增删改的时候都要基于最新的数据进行增删改。
而select…for update原理是:对查询范围内的数据进行加锁,不允许其它事务对这个范围内的数据进行增删改。也就是说这个select语句范围内的数据是不允许并发的,只能排队执行,从而避免幻读问题。
select…for update加的锁叫做:next-key lock。我们可以称其为:间隙锁 + 记录锁。间隙锁用来保证在锁定的范围内不允许insert操作。记录锁用来保证在锁定的范围内不允许delete和update操作。

假如有这样的数据:
image.png
SQL语句是这样写的:

select * from a where id between 2 and 4 for update;

那么id在[2-4]区间的所有记录行被锁定,不能插入3是通过间隙锁来搞定的。不能修改或删除2和4是通过记录锁来搞定的。

演示:

事务A事务B
mysql> use powernode
mysql> use powernode
mysql> start transaction;
mysql> start transaction;
mysql> select * from a where id between 2 and 4 for update; // 当前读
image.png

出现幻读的两种情况

在同一个事务处理过程中,如果前后两次都采用快照读,或者都采用当前读,则不会出现幻读问题。如果第一次使用快照读,后面使用了当前读,则会出现幻读问题。

第一种产生幻读的场景

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

事务A事务B
mysql> use powernode
mysql> use powernode
mysql> start transaction;
mysql> start transaction;
mysql> select * from a;
image.png
mysql> insert into a values(5);
mysql> commit;
mysql> select * from a for update; // 产生了幻读
image.png
第二种产生幻读的场景

事务A与事务B,在事务A中第一次查询使用快照读,在事务B中插入一条数据,然后在事务A中更新事务B插入的那条记录,最后在事务A中再次使用快照读。则会发生幻读现象。

事务A事务B
mysql> use powernode
mysql> use powernode
mysql> start transaction;
mysql> start transaction;
mysql> select * from a;
image.png
mysql> insert into a values(6);
mysql> commit;
mysql> update a set id=100 where id=6; //主要是因为这个SQL语句的执行触发了当前读
mysql> select * from a; // 产生了幻读
image.png

总结可重复读的幻读问题

MySQL的可重复读隔离级别(默认隔离级),根据不同的查询方式,分别提出了避免幻读的方案:

  • 针对快照读(普通 select 语句),是通过 MVCC 方式解决了幻读。
  • 针对当前读(select … for update 等语句),是通过 next-key lock(记录锁+间隙锁)方式解决了幻读。

我举例了两个发生幻读场景的例子。

  • 第一个例子:对于快照读, MVCC 并不能完全避免幻读现象。因为当事务 A 更新了一条事务 B 插入的记录,那么事务 A 前后两次查询的记录条目就不一样了,所以就发生幻读。
  • 第二个例子:对于当前读,如果事务开启后,并没有执行当前读,而是先快照读,然后这期间如果其他事务插入了一条记录,那么事务后续使用当前读进行查询的时候,就会发现两次查询的记录条目就不一样了,所以就发生幻读。

所以,MySQL 可重复读隔离级别并没有彻底解决幻读,只是很大程度上避免了幻读现象的发生。
要避免这类特殊场景下发生幻读的现象的话,就是尽量在开启事务之后,马上执行 select … for update 这类当前读的语句,因为它会对记录加 next-key lock,从而避免其他事务插入一条新记录。

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

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

相关文章

一文带你了解神经网络是如何学习预测的

文章目录 1、GPT与神经网络的关系 2、什么是神经网络 3、神经网络是如何计算的 数据是如何输入到神经网络中的 神经网络是如何进行预测的 神经网络是如何进行学习的 4、小结 1、GPT与神经网络的关系 GPT想必大家已经耳熟能详&#xff0c;当我们与它进行对话时&#xff0c;通常…

人民艺术家、中国书画院院士王家才

人民艺术家王家才 在中国画坛的广袤土地上&#xff0c;一位名叫王家才的艺术家以其深厚的艺术造诣和独特的艺术风格&#xff0c;赢得了“人民艺术家”的殊荣。她的作品不仅在国内受到广泛赞誉&#xff0c;还多次走出国门&#xff0c;成为中外文化交流的桥梁。 王家才女士是一…

springboot项目自定义切面增强方法功能(springboot记录日志)

说明 背景&#xff1a;记录系统接口日志入库&#xff0c;包含接口方法、入参、回参、响应时间、操作人、操作时间等信息。 方案&#xff1a;添加自定义切面处理 一、自定义切面注解 package com.gstanzer.supervise.annotation;import com.gstanzer.supervise.enums.Busine…

C语言中,可以在子函数中动态申请一个指向二维数组的内存给调用函数使用么——看ChatGPT的回答——

下面是ChatGPT的回答&#xff0c;太专业了&#xff0c;比网上查的资料都好很多可能。 是的&#xff0c;可以在子函数中动态申请一个指向二维数组的内存&#xff0c;然后将其传递给调用函数使用。在C语言中&#xff0c;可以通过以下方式实现&#xff1a; #include <stdio.h…

7、Design Script之自定义函数

关联式编程 VS. 命令式编程 关联式编程使用图依赖的概念来建立“流控制”。Associative是代码块内的默认模式。 命令式编程的特点是使用“For”和“While”循环进行显式流控制(用于迭代)和if/elseif/else语句(用于条件语句),要初始化命令式代码,你可以使用以下语法: [Impe…

【LeetCode: 2684. 矩阵中移动的最大次数 + dfs】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

Webapi(.net6) 批量服务注册

如果不考虑第三方库&#xff0c;如Autofac这种进行服务注入&#xff0c;通过本身的.Core Weabpi实现的&#xff0c;总结了两种实现方法&#xff0c; 1.一种是参考abp框架里面的形式; 1.1 新建个生命周期的文件夹: 三个接口分别为: public interface IScopedDependency { }pu…

vs实用调试技巧

前言&#xff1a; 我们在写程序的时候可能多多少少都会出现一些bug&#xff0c;使我们的程序不能正常运行&#xff0c;所以为了更快更好的找到并修复bug&#xff0c;使这些问题迎刃而解&#xff0c;学习好如何调试代码是每个学习编程的人所必备的技能。 1. 什么是bug&#xf…

html canvas怎么在图片上面加文字

在HTML canvas中&#xff0c;要让文字显示在图片上方&#xff0c;你需要按照以下步骤操作&#xff1a; 首先&#xff0c;使用drawImage()方法将图片绘制到canvas上。 然后&#xff0c;使用fillText()或strokeText()方法在canvas上绘制文本。 以下是一个简单的示例代码&#…

C#Socket通信实现

1.编写服务端代码&#xff0c;以原石兑换码为例&#xff08;分别建立两个控制台应用&#xff0c;一个用于服务端&#xff0c;一个用于客户端&#xff09; using System.Net.Sockets; using System.Net; using System.Text;namespace 网络游戏服务器 {internal class Program{s…

【Eviews实战】——重庆市居民消费城乡差异研究

&#x1f349;CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一&#xff5c;统计学&#xff5c;干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项&#xff0c;参与研究经费10w、40w级横向 文…

Python内存管理与垃圾回收机制:深入理解与优化【第138篇—RESTful API】

Python内存管理与垃圾回收机制&#xff1a;深入理解与优化 在Python编程中&#xff0c;内存管理与垃圾回收机制是至关重要的主题。了解Python如何管理内存和处理垃圾回收对于编写高效、稳定的程序至关重要。本文将深入探讨Python中的内存管理和垃圾回收机制&#xff0c;包括内…

【ARM】UBL本地服务器离线激活license

【更多软件使用问题请点击亿道电子官方网站查询】 1、 文档目标 UBL本地服务器离线激活license。 2、 问题场景 解决有用户外出时激活 license。 3、软硬件环境 1&#xff09;、软件版本&#xff1a;MDK5.39 2&#xff09;、电脑环境&#xff1a;Ubuntu 20.04 LTS 3&…

【Eviews实战】——时序的平稳性检验

&#x1f349;CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一&#xff5c;统计学&#xff5c;干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项&#xff0c;参与研究经费10w、40w级横向 文…

Microsoft OneDrive的10个常见问题及其解决方法,总有一种适合你

前言 Microsoft OneDrive是一个有用的工具,用于在线和跨多个设备备份和同步文件。然而,问题和冲突确实会发生。可能OneDrive突然停止工作,文件无法同步,项目被意外删除,或者同一文件的两个版本出现。然而,在你转到其他云存储服务之前,下面是如何解决这些(和其他)常见…

基于openresty构建运维工具链实践

本文字数&#xff1a;4591字 预计阅读时间&#xff1a;25 01 导读 如今OpenResty已广泛被各个互联网公司在实际生产环境中应用&#xff0c;在保留Nginx高并发、高稳定等特性基础上&#xff0c;通过嵌入Lua来提升在负载均衡层的开发效率并保证其高性能。本文主要介绍接口鉴权、流…

3款文章生成器,为创作者高效率自动写文章

在当今信息爆炸的时代&#xff0c;写作已经成为许多人不可或缺的技能。无论是从事新闻行业、营销领域&#xff0c;还是个人博客的作者&#xff0c;都需要不断地输出高质量的文字内容来吸引读者。然而&#xff0c;对于许多创作者来说&#xff0c;写作是一个耗时耗力的过程&#…

Python环境安装与配置(Windows环境)

Python目前已支持所有主流操作系统&#xff0c;在Linux,Unix,Mac系统上自带Python环境&#xff0c;在Windows系统上需要安装一下&#xff0c;超简单 一、下载Python 打开官网 Download Python | Python.org 下载中心&#xff0c;根据自己的系统和版本选择合适的安装包&#xf…

一款强大的去重工具,让文章快速过原创

今天要给大家分享的内容是一款强大的去重工具&#xff0c;可以帮助我们在创作的过程中让文章快速过原创检测&#xff01;我们都知道&#xff0c;在当今信息爆炸的时代&#xff0c;网络上充斥着大量的内容&#xff0c;原创性已经成为内容创作者们追求的重要目标之一。然而&#…

Postman-Installation has failed

如图&#xff1a; 解决方法&#xff1a; 打开文件夹 Postman-win64-Setup 点击Postman.exe 即可