mysql脏读,不可重复读,幻读及事务级别的理解(结合代码去理解案例你会焕然大悟)

本文主要是介绍mysql脏读,不可重复读,幻读及事务级别的理解(结合代码去理解案例你会焕然大悟),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文目录

    • 前言
    • 脏读
    • 不可重复读
    • 幻读
    • 三者区别:
    • SQL标准定义了4类隔离级别
      • Read Uncommitted(读取未提交内容)
      • Read Committed(读取提交内容)
      • Repeatable Read(可重读)
      • Serializable(可串行化)
    • 4类隔离级别总结

前言

要从微观的角度去理解事物,不要从宏观的角度去看待事物。脏读,不可重复读,幻读。都是在一个操作下,不要理解成我们进行多次操作看到的结果不一样。要注意看着代码来理解。(刚刚学这个的时候我就理解成了,用户多次操作,看到的结果不一样,数值是没错的只是没更新而已。这是一个误区!!)

脏读

一个事务读到另一个事务,尚未提交的修改,就是脏读。这里所谓的修改,除了Update操作,不要忘了,还包括Insert和Delete操作。脏读的后果:如果后一个事务回滚,那么它所做的修改,统统都会被撤销。前一个事务读到的数据,就是垃圾数据。
脏读是很严重的。
在这里插入图片描述
可以看到在T6的时候转账获取余额是900。T7的时候回滚了数据余额应该是1000。可是转账事务余额是900。存100就变成了900+100=1000。可以看看代码,看着代码结合上图应该好理解点。

 //转账事务public void addCount(){//查余额剩余多少T6Integer money = selectMoneyById(id);/*** money=900;** T7这时取钱那边回滚了。** money=1000才是对的。**可是变量money 还是 900* **///存一百块int add=100;int result = money+add;//900+100=1000(T8}

不可重复读

在同一个事务中,再次读取数据时【就是你的select操作】,所读取的数据,和第1次读取的数据,不一样了。就是不可重复读。

你启动一个事务,并做一个select查询操作。查询到的数据,就有可能,和你第2次,3次…n次,查询到的数据不一样。一般情况下,你只会做一次,select查询,并以这一次的查询数据,作为后续计算的基础。因为允许出现,不可重复读。那么任何时候,查询到的数据,都有可能被其他事务更新,查询的结果将是不确定的。

例子看图
在这里插入图片描述
在T4时转账事务的查出来还有1000块钱。T5时刻取钱事务取了100块,余额应该是900才对。可是转账事务还是按照1000来算。1000+100=1100;
代码解释:

 //转账事务public void addCount(){//查余额剩余多少T4Integer money = selectMoneyById(id);/*** money=1000;** T5这时取走了100。** money=900才是对的。** **///存一百块int add=100;int result = money+add;//1000+100=11000(T7}

幻读

事务1读取指定的where子句所返回的一些行。然后,事务2插入一个新行,这个新行也满足事务1使用的查询where子句。然后事务1再次使用相同的查询读取行,但是现在它看到了事务2刚插入的行。这个行被称为幻象,因为对事务1来说,这一行的出现是不可思议的。
例子:
都知道用户账号是唯一的。每次新增用户就要判断一下账号是否存在。事务一要新增一个账号为:123 的用户。事务二也要增加一个账号:123的用户
有了这个前提我们一起看代码:

 public void addUser(){//事务一要新增一个账号为123的用户//根据账号id去查是否存在123的用户boolean userIsExist = selectUserById("123");/*** 假设现在是没有账号为123用户的。userIsExist=false* * 在这时事务二插入了账号为123的用户* * 可是这里userIsExist的值还是false* * */if(!userIsExist){//不存在123的用户才可以新增//开始新增用户insertUser("123");}}

幻读是针对插入和删除的。

三者区别:

脏读的重点是读另一个事务未提交的数据(假若那个事务RollBack, 则这数据就是无效的):某个事务已更新一份数据, 另一个事务在此时读取了同一份数据, 由于某些原因, 前一个RollBack了操作, 则后一个事务所读取的数据就会是不正确的

不可重复读的重点是修改: 同样的条件, 事务读取过的数据, 再次读取出来发现值不一样了

幻读的重点在于新增或者删除: 同样的条件, 第1次和第2次读出来的记录数不一样
当然, 从总的结果来看, 似乎不可重复读和幻读都表现为两次读取的结果不一致, 但如果你从控制的角度来看, 两者的区别就比较大, 对于不可重复读, 只需要锁住满足条件的记录, 对于幻读, 要锁住满足条件及其相近的记录。

注意:多次操作不一样不是我们去点击,操作多次看到的值不一样。是程序,看到值不一样是针对程序内部来说的,不理解可以看回上面代码去理解。

SQL标准定义了4类隔离级别

4类隔离级别包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。

Read Uncommitted(读取未提交内容)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

Read Committed(读取提交内容)

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

Repeatable Read(可重读)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

Serializable(可串行化)

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。只要操作产生了锁,就不允许其他事务读取和修改!

4类隔离级别总结

在这里插入图片描述
应该明白 什么状况对什么加什么锁(可以分别思考和测试每个隔离级别下脏读、不可重复读、幻读的出现及不出现原因)

不可重复读错误处理:通常可以用 set tran isolation level repeatable read 来设置隔离级别, 这样事务 A 在两次读取表T中的数据时, 事务B如果企图更改表T中的数据(细节到事务A读取数据)时, 就会被阻塞, 直到事务A提交! 这样就保证了, 事务A两次读取的数据的一致性(就不允许两个事物同时读取,修改一个值,要排队等待一个一个来)

幻读错误处理:如果设置 repeatable read, 虽然可以防止事务B对数据进行修改, 但是事务B却可以向表T中插入新的数据, 如何防止这个问题, 我们可以考虑设置最高的事务隔离级别 set tran isolation level serializable, 于是乎, 事务B就只能乖乖的等待事务A的提交, 才能向表T中插入新的数据, 从而避免了幻读(要避免幻读要把表锁住,性能就会很低,开发中很少这么做)

这篇关于mysql脏读,不可重复读,幻读及事务级别的理解(结合代码去理解案例你会焕然大悟)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/539075

相关文章

PostgreSQL的扩展dict_int应用案例解析

《PostgreSQL的扩展dict_int应用案例解析》dict_int扩展为PostgreSQL提供了专业的整数文本处理能力,特别适合需要精确处理数字内容的搜索场景,本文给大家介绍PostgreS... 目录PostgreSQL的扩展dict_int一、扩展概述二、核心功能三、安装与启用四、字典配置方法

MySQL 中的 CAST 函数详解及常见用法

《MySQL中的CAST函数详解及常见用法》CAST函数是MySQL中用于数据类型转换的重要函数,它允许你将一个值从一种数据类型转换为另一种数据类型,本文给大家介绍MySQL中的CAST... 目录mysql 中的 CAST 函数详解一、基本语法二、支持的数据类型三、常见用法示例1. 字符串转数字2. 数字

Mysql实现范围分区表(新增、删除、重组、查看)

《Mysql实现范围分区表(新增、删除、重组、查看)》MySQL分区表的四种类型(范围、哈希、列表、键值),主要介绍了范围分区的创建、查询、添加、删除及重组织操作,具有一定的参考价值,感兴趣的可以了解... 目录一、mysql分区表分类二、范围分区(Range Partitioning1、新建分区表:2、分

MySQL 定时新增分区的实现示例

《MySQL定时新增分区的实现示例》本文主要介绍了通过存储过程和定时任务实现MySQL分区的自动创建,解决大数据量下手动维护的繁琐问题,具有一定的参考价值,感兴趣的可以了解一下... mysql创建好分区之后,有时候会需要自动创建分区。比如,一些表数据量非常大,有些数据是热点数据,按照日期分区MululbU

SQL Server配置管理器无法打开的四种解决方法

《SQLServer配置管理器无法打开的四种解决方法》本文总结了SQLServer配置管理器无法打开的四种解决方法,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录方法一:桌面图标进入方法二:运行窗口进入检查版本号对照表php方法三:查找文件路径方法四:检查 S

MySQL 删除数据详解(最新整理)

《MySQL删除数据详解(最新整理)》:本文主要介绍MySQL删除数据的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、前言二、mysql 中的三种删除方式1.DELETE语句✅ 基本语法: 示例:2.TRUNCATE语句✅ 基本语

MySQL中查找重复值的实现

《MySQL中查找重复值的实现》查找重复值是一项常见需求,比如在数据清理、数据分析、数据质量检查等场景下,我们常常需要找出表中某列或多列的重复值,具有一定的参考价值,感兴趣的可以了解一下... 目录技术背景实现步骤方法一:使用GROUP BY和HAVING子句方法二:仅返回重复值方法三:返回完整记录方法四:

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

Spring事务传播机制最佳实践

《Spring事务传播机制最佳实践》Spring的事务传播机制为我们提供了优雅的解决方案,本文将带您深入理解这一机制,掌握不同场景下的最佳实践,感兴趣的朋友一起看看吧... 目录1. 什么是事务传播行为2. Spring支持的七种事务传播行为2.1 REQUIRED(默认)2.2 SUPPORTS2

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优