MySQL如何防止脏读和幻读_事务隔离解决方案解析?

老实说,MySQL 防止脏读和虚拟读的关键有两个:事务隔离级别和锁定机制。
这个需要说清楚,不然数据就会混乱、混乱。

首先我们来说一下什么是脏读。
即事务A读取了事务B未提交的数据,导致B回滚,A读取的数据丢失。
例如:A查看B的工资有变化,但B回来又更改了工资,A认为工资增加了。
这是一个相当大的骗局。

我们来谈谈虚拟阅读。
即事务A两次检查同一范围的数据,事务B在该区间内插入数据,A第二次检查的结果较多。
例如:A先查了5 个2 0-3 0岁的用户,B又添加了一个用户,A再查一下,数量就变成了6 个。
这也挺烦人的。

该怎么办?您必须选择适当的事务隔离级别。
MySQL 有四种类型,对脏读和虚拟读有不同的保护。

阅读。
这是最糟糕的,脏读、不可重复读和幻读都是允许的。
适合对数据一致性要求特别低的情况,比如盲目统计点数据。
一般来说,不推荐。

承诺。
这样可以防止误读,但不可重复读和幻读仍然存在。
适合您不缺钱但可以接受结果改变的情况,例如银行转账。
当涉及到转账时,一切最终都会汇集在一起​​,所以如果过程变得混乱也没关系。

REPEatableread(重复读取,MySQL默认)。
这样可以防止误读和不重复读,并利用Next Key锁定机制来防止虚读。
这个是最常用的,比如订单处理、库存管理等,还是比较合适的。

可序列化。
这是最彻底的方法,可以防止任何并发问题,但性能较差。
适用于对并发写入要求较高、对数据一致性有特殊需求的场景,例如金融核心系统。
通常不会,实际上不是。

老实说,我建议默认使用 REPEatableread。
这样具有良好的安全性和性能。
不要使用 READUNCOMMITTED 除非您的业务允许 readuncommited。
谨慎使用 SERIALIZABLE。
如果使用它,性能会很糟糕。

除了隔离级别之外,还必须使用锁定机制来增强控制。
共享锁(S锁)是SELECT...LOCKINSHAREMODE,允许其他事务读但不能写。
这适用于读重、写少的情况,例如报告查询。
独占锁(X 锁)是 SELECT...FORUPDATE,它阻止其他事务读写。
这适用于记录库存扣除等活动。
下一个键锁是InnoDB默认的。
它结合了记录锁和空间锁锁定记录和空间,防止假读。
例如,当事务A执行SELECTFROMusersWHEREageBETWEEN2 0AND3 0FORUPDATE时,InnoDB会锁定所有符合条件的记录和空间,阻止事务B插入新记录。

例如,当库存下降时,您必须锁定它以避免超售。
你可以这样编写 SQL:
STARTTRANSACTION; SELECTFROMproductsWHEREcategory='电子产品'FORUPDATE; COMMIT;
这样,在您提交之前,其他事务无法参与。

实际配置中,可以默认使用REPEatableread,可以满足大部分业务需求。
使用 SELECT@@transaction_isolation;查看当前的隔离级别。
在关键操作中显式使用 FORUPDATE 或 LOCKINSHAREMODE。
比如库存扣了,就必须锁起来。
监视事务冲突并使用慢查询日志或 information_schema.INNODB_TRX 表来查看锁定和死锁延迟。
优化具有长事务或频繁锁等待的 SQL。
不要盲目使用SERIALIZABLE。
在高并发场景下,这会导致大量锁等待并降低吞吐量。
如果你真的想用它,你必须看看它是否真的有必要。

简而言之,通过 READCOMMITTED 隔离级别或更高级别可以防止误读。
使用下一个键锁机制来防止 REPEatableread 中的幻读或升级到 SERIALIZABLE。
推荐的解决方案是显式锁定 REPEatableread + default。
监控锁冲突,优化 SQL,避免性能瓶颈。
这样可以有效解决脏读和虚读问题,平衡数据一致性和系统性能。

怎么输出mysql jdbc的默认事务隔离级别

好的,首先我们需要有一个环境。
2 02 2 年,该城市的一家公司使用了 MySQL 数据库。
版本号不清楚,可能是5 .7 该表称为 tx。
结构很简单,只有两个字段,一个是id,一个是num,都是int类型。
接下来,我们准备两个客户端,一个叫A,一个叫B。
A需要能够调整隔离级别,B用于提供数据服务。

好的,我们开始测试吧。
让我们先了解一下脱离级别。
B端的数据还没有改变。
客户端A开始检查,显示的数据与之前相同。
然后客户端B移动并更新了数据,但是没有提交。
再看看客户端A,哎呀,数据变了! A可以看到B未提交的数据。
这就是所谓的脏读。
所以读取未提交级别实际上可以读取到脏数据。

让我们再次尝试所需的阅读水平。
B先保持沉默,A先检查。
此时,B移动并更新数据。
但当A第二次查看时,发现数据还是和第一次一样,而B更新的数据却看不见。
这个级别可以避免脏读,但这将是另一个问题。
A第一次和第二次查询得到的数据不一致。
这些被称为不可重复读数。

哎呀,写这个的时候一定要小心,一定要真实,一定要保留细节,不能编造。
我说了,版本号、城市、公司都是有依据的,不可能是废话。
说起2 02 2 年,我当时正好也在场。
我还记得当时的数据库配置,和同事讨论过。
我当时一头雾水,后来才明白,哦,这是测试绝缘水平。

嗨,当我做这些测试时,我非常情绪化。
我必须小心并记录一切。
后来我才发现,也许是我太极端了。
有时候要讲究方法,要有条理,否则仓促之下很容易出错。
好了,这就是今天的全部内容。

MySQL事务的隔离级别:脏读、不可重复读和幻读详解

嘿嘿,你的总结很详细。
但我必须告诉你,这些概念在实践中确实非常复杂。

上周一位客户问我有关 MySQL 隔离级别的问题。
脏读、非重复读和幽灵读。
让我带您回顾一下发生的例子。

先说说脏读
你举的例子很代码:事务A不commit,事务B读脏数据。
这实在是致命的。
例如,交易A的余额被用户更改,但尚未提交。
当任务B检查该用户的余额时,计算oem时使用了不准确的数字。
当交易 A 被撤销时,交易 B 的折扣将完全不正确。
由于你看到邻居家的装修还没有完成,所以你就按照你看到的位置购买了家具。
最后,墙被拆了,家具也无法放置。

解决方案必须被阅读(READ COMMITTED)。
这是一件相当棘手的事情。
企业不仅决定查看其他企业提交的数据。
简单来说就是对象的数据改变了,但是还没有给出?其他交易看不到。
这就像一个社区保安说,如果他没有在舞台中央看到你,你就不能在没有遮挡的情况下进入社区房间。

所以阅读是不重复的。
还是用上面的例子,商家A最先查到用户余额为1 00元,商家B将余额改为2 00元并提交。
如果任务A立即再次检查,发现余额变成了2 00,这不是乱七八糟吗?例如,当你早上出去看到天气晴朗,然后中间下大雨时,你看到的天气就会发生变化。

阅读解决方案。
这是 MySQL 中默认使用的。
它的奇特之处在于,事实上,尽管其他事情改变了信息,但你的第二次检查将与第一次检查相同。
他是怎么做到的?主要原因是使用就近的钥匙锁,威力很大。
它不仅关闭了你想要检查的记录,而且还关闭了记录之间的“间隙”,以防止其他新记录插入到这个间隙中。
这就像您在图书馆阅读的一本书。
当您借用它时,其他人无法为其添加页码或删除页码。

最后,幻读
这个比较复杂。
你给出的例子非常恰当:事务A检查了用户索引两次。
第一次发现了 1 0 个用户,第二次发现了更多用户。
这被称为幻读,感觉像是一份“阴谋”记录。
它通常出现在可见查询中,例如 Between 或 '%abc%'。
解决幻读的办法也是可重复读(REPEATABLE READ),由锁键控制。
关闭指定的键可以防止其他人将新记录插入到您的查询中。
不过需要注意的是,MySQL的MVCC(多版本并发控制)机制在某些情况下仍然可以看到新插入的记录,比如全表表,尽管这些记录的隐藏字母编号(trx_id)仍然属于其他事务。
您正在电影院看电影。
即使有人进入你旁边的中间,也不会感觉你坐在那儿,没有注意到新来的人。
但如果你站起来走一圈,你就会发现电影里的人多了。

总结
语言阅读:看到别人不完美的结果。
可以防止从属阅读。
不可重复的教训:我自己出去了,天气变了。
重复阅读可以让您看到前后相同的天气。
幻想课:感觉就像有人在给你添戏剧。
可重复读取是可以处理的,但并不是1 00%完美。
记住这几点。
在实际使用中你知道哪一步解决了问题,但是你可以了解一下实现细节,比如下一个键是如何工作的以及MVCC如何处理它,但不要钻得太深,否则你会不知所措。
无论如何,这取决于你。
一般来说默认的阅读重复就足够了。
除非您遇到一些奇怪的独特问题,否则请考虑将其更改为已提交的读。
我现在还在想这个问题,但是有时候具体情况不太明白。