百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

「数据库架构」事务隔离级别和脏读快速入门

mhr18 2024-09-18 20:22 14 浏览 0 评论

重要要点


  • 仅凭ACID或非ACID来思考,还需要知道数据库支持的隔离级别。
  • 标榜为“最终一致”的某些数据库可能返回与任何时间点不一致的结果。
  • 一些数据库提供的隔离级别比您要求的更高。
  • 脏读会导致您看到同一记录的两个版本,或者完全错过一条记录。
  • 在单个事务中多次重新运行查询时,可能会出现幻像行。

最近,当开发人员David Glasser了解MongoDB默认执行脏读的糟糕方式时,MongoDB再次成为Reddit的佼佼者。 在本文中,我们将解释什么是隔离级别和脏读以及如何在流行的数据库中实现它们。

在ANSI SQL中,有四个标准隔离级别:可序列化,可重复读取,已提交读取和未提交读取。

许多数据库的默认设置为“读取已提交”,它仅保证在进行该事务时您不会看到过渡中的数据。它通过在读取期间短暂地获取锁来实现此目的,同时保持写入锁直到事务被提交。

如果您需要在一个事务中多次重复相同的读取操作,并且想要合理地确定它总是返回相同的值,则需要在整个持续时间内保持读取锁定。使用“可重复读取”隔离级别时,将自动为您完成此操作。

我们说“可重复读”是“合理肯定的”,因为可能存在“幻读”。使用where子句(例如“ WHERE Status = 1”)执行查询时,可能会发生幻像读取。这些行将被锁定,但是没有什么阻止添加符合条件的新行。术语“幻像”适用于第二次执行查询时出现的行。

为了绝对确保同一事务中的两次读取返回相同的数据,可以使用Serializable隔离级别。这使用“范围锁”,如果新行与打开的事务中的WHERE子句匹配,则可以防止添加这些行。

通常,隔离级别越高,由于锁争用而导致的性能越差。因此,为了提高读取性能,某些数据库还支持“读取未提交”。此隔离级别忽略锁(实际上在SQL Server中称为NOLOCK)。结果,它会执行脏读。

脏读问题

在讨论脏读之前,您必须了解表实际上并不存在于数据库中。表只是一个逻辑构造。实际上,您的数据存储在一个或多个索引中。在大多数关系数据库中,主索引被称为“聚集索引”或“堆”。 (对于NoSQL数据库,术语有所不同。)因此,在执行插入操作时,它需要在每个索引中插入一行。执行更新时,数据库引擎仅需要触摸引用正在更改的列的索引。但是,它通常必须对每个索引执行两次操作,即从旧位置删除和向新位置插入。

在下图中,您可以看到一个简单的表和一个执行计划,其中更新了两个对象IX_Customer_State和PK_Customer。由于全名未更改,因此跳过了IX_Customer_FullName索引。


注意:在SQL Server中,PK前缀是指主键,它通常也是用于聚集索引的键。 IX用于非聚集索引。 其他数据库有其自己的约定。

通过这种方式,让我们看一下脏读可能导致数据不一致的多种方式。

未提交的读取最容易理解。 通过忽略写锁定,使用“读未提交”的SELECT语句可以在事务完全提交之前看到新插入或更新的行。 如果该转换然后被回滚,那么从逻辑上讲,SELECT操作将返回从不存在的数据。

在更新操作期间移动数据时,会发生两次读取。 假设您正在按州读取所有客户记录。 如果上述更新语句是在您加州记录的时间与您阅读德克萨斯州记录的时间之间执行的,则您可以看到客户1253两次; 一次使用旧值,一次使用新值。

漏读的发生方式相同。 如果我们将客户1253移到德克萨斯州到阿拉斯加,再按州选择数据,则可能会完全错过该记录。 这就是David Glasser的MongoDB数据库所发生的事情。 通过在更新操作期间从索引读取,查询会丢失记录。


根据数据库的设计方式和特定的执行计划,脏读也会干扰排序。例如,如果执行引擎收集指向所有感兴趣的行的一组指针,然后更新一行,然后执行引擎实际上使用所述指针从原始位置复制数据,则可能发生这种情况。

快照隔离或行级别版本控制

为了提供良好的性能同时避免脏读问题,许多数据库都支持快照隔离语义。在快照隔离下运行时,当前事务无法查看在当前事务之前启动的任何其他事务的结果。

这是通过制作要修改的行的临时副本来完成的,而不是仅仅依靠锁。这通常称为“行级版本控制”。

当请求读取提交隔离时,大多数支持快照隔离语义的数据库都会自动使用它。

SQL Server中的隔离级别

SQL Server支持所有四个ANSI SQL隔离级别以及一个显式的快照级别。取决于使用READ_COMMITTED_SNAPSHOT选项配置数据库的方式,“已提交读”也可以使用快照语义。

在启用此选项之前和之后,请彻底测试数据库。虽然它可以提高读取性能,但可能会减慢写入速度。如果您的tempdb处于慢速驱动器上,则尤其如此,因为这是行的旧版本存储的地方。

臭名昭著的NOLOCK指令(可应用于SELECT语句)与在设置为“读取未提交”的事务中运行具有相同的效果。由于SQL Server 2000和更早版本尚未提供行级版本控制,因此该版本已大量使用。尽管不再需要或不建议使用,但该习惯仍然存在。

有关更多信息,请参见SET TRANSACTION ISOLATION LEVEL(Transact-SQL)。

PostgreSQL中的隔离级别

虽然PostgreSQL正式支持所有四个ANSI隔离级别,但实际上它只有三个。每当查询请求“读取未提交”时,PostgreSQL都会以静默方式将其升级为“读取已提交”。因此PostgreSQL不允许脏读。

当选择级别Read Uncommitted时,您实际上会获得Read Committed,并且在Repeatable Read的PostgreSQL实现中不可能进行幻像读取,因此实际的隔离级别可能比您选择的严格。这是SQL标准所允许的:四个隔离级别仅定义了哪些现象一定不能发生,它们没有定义哪些现象必须发生。

PostgreSQL没有明确提供快照隔离。而是在使用“读取已提交”时自动发生。这是因为PostgreSQL从一开始就设计为具有多版本并发控制。

在9.1版之前,PostgreSQL不提供可序列化的事务,并且会静默地将它们降级为“可重复读”。当前没有支持的PostgreSQL版本仍然具有此限制。

有关更多信息,请参见13.2。事务隔离。

MySQL中的隔离级别

InnoDB默认为“可重复读取”,但提供所有四个ANSI SQL隔离级别。读取已提交使用快照隔离语义。

有关InnoDB的更多信息,请参见15.3.2.1事务隔离级别。

使用MyISAM存储引擎时,根本不支持事务。相反,它在表级别使用一个读写器锁。 (尽管在某些情况下,插入操作可以绕过锁。)

Oracle中的隔离级别

Oracle仅支持3个事务级别:读已提交,可序列化和只读。在Oracle中,“默认值为读已提交”,它使用快照语义。

像PostgreSQL一样,Oracle不提供“读未提交”。绝对不允许脏读。

列表中还缺少“可重复读取”。如果您在Oracle中需要这种行为,则需要将隔离级别设置为Serializable。

Oracle唯一的隔离级别是只读。它没有很好的文档记录,手册只说:

只读事务仅查看那些在事务开始时提交的更改,并且不允许INSERT,UPDATE和DELETE语句。

有关其他两个隔离级别的更多信息,请参阅13数据并发性和一致性。

DB 2中的隔离级别

DB 2具有4个隔离级别,分别称为重复读取,读取稳定性,游标稳定性和未提交读取。但是,它们并不直接映射到ANSI术语。

可重复读是ANSI SQL称为可序列化的。也就是说,幻像读取是不可能的。

读取稳定性映射到ANSI SQL的可重复读取。

默认情况下,“游标稳定性”用于“读取已提交”。从9.7版开始,快照语义已生效。以前,它将使用类似于SQL Server的锁。

未提交读允许进行脏读,就像SQL Server的未提交读一样。该手册仅建议将其用于只读表,或者“在查看其他应用程序未提交的数据没有问题时”。

有关更多信息,请参见隔离级别。

MongoDB中的隔离级别

如前所述,MongoDB不支持事务。从手册中

由于MongoDB仅单文档操作是原子操作,因此两阶段提交只能提供类似于事务的语义。在两阶段提交或回滚期间,应用程序有可能在中间点返回中间数据。

实际上,这意味着MongoDB使用脏读语义,其中包括记录可能翻倍或丢失的可能性。

CouchDB中的隔离级别

CouchDB也不支持交易。但是与MongoDB不同,它确实使用多版本并发控制来防止脏读。

读取请求在请求开始时始终会看到您数据库的最新快照。

这使CouchDB等效于具有Snapshot语义的Read Committed隔离级别。

有关更多信息,请参见最终一致性。

Couchbase服务器中的隔离级别

尽管经常与CouchDB混淆,但Couchbase Server是一个非常不同的产品。对于索引,它没有隔离的概念。

在执行更新时,它仅更新主索引,如果您愿意,也可以更新“真实表”。所有二级索引均会延迟更新。

该文档尚不清楚,但在建立索引时似乎使用快照。如果是这样,脏读应该不是问题。但是由于延迟索引更新,您仍然无法获得真正的“读取已提交”隔离级别。

与许多NoSQL数据库一样,它不直接支持事务。但是,您确实可以使用显式锁。这些只能保留30秒,然后自动丢弃。

有关更多信息,请参阅锁定项目,您需要了解的有关Couchbase体系结构的所有信息以及Couchbase View Engine内部。

Cassandra的隔离级别

在Cassandra 1.0中,甚至没有隔离写入单个行。字段是一一更新的,因此您最终可能会读取包含新旧值的记录。

从1.1版开始,Cassandra提供“行级隔离”。这使其达到与其他数据库称为“读取未提交”的相同隔离级别。更高级别的隔离是不可能的。

有关更多信息,请参见关于事务和并发控制。

了解数据库的隔离级别

从上面的示例中可以看到,仅将数据库视为ACID或非ACID是不够的。 您确实需要知道它支持什么隔离级别以及在什么情况下。

原文:https://www.infoq.com/articles/Isolation-Levels/

本文:http://jiagoushi.pro/node/918

讨论:请加入知识星球或者微信圈子【首席架构师圈】

相关推荐

Redis合集-使用benchmark性能测试

采用开源Redis的redis-benchmark工具进行压测,它是Redis官方的性能测试工具,可以有效地测试Redis服务的性能。本次测试使用Redis官方最新的代码进行编译,详情请参见Redis...

Java简历总被已读不回?面试挂到怀疑人生?这几点你可能真没做好

最近看了几十份简历,发现大部分人不是技术差,而是不会“卖自己”——一、简历死穴:你写的不是经验,是岗位说明书!反面教材:ד使用SpringBoot开发项目”ד负责用户模块功能实现”救命写法:...

redission YYDS(redission官网)

每天分享一个架构知识Redission是一个基于Redis的分布式Java锁框架,它提供了各种锁实现,包括可重入锁、公平锁、读写锁等。使用Redission可以方便地实现分布式锁。red...

从数据库行锁到分布式事务:电商库存防超卖的九重劫难与破局之道

2023年6月18日我们维护的电商平台在零点刚过3秒就遭遇了严重事故。监控大屏显示某爆款手机SKU_IPHONE13_PRO_MAX在库存仅剩500台时,订单系统却产生了1200笔有效订单。事故复盘发...

SpringBoot系列——实战11:接口幂等性的形而上思...

欢迎关注、点赞、收藏。幂等性不仅是一种技术需求,更是数字文明对确定性追求的体现。在充满不确定性的网络世界中,它为我们建立起可依赖的存在秩序,这或许正是技术哲学最深刻的价值所在。幂等性的本质困境在支付系...

如何优化系统架构设计缓解流量压力提升并发性能?Java实战分享

如何优化系统架构设计缓解流量压力提升并发性能?Java实战分享在高流量场景下。首先,我需要回忆一下常见的优化策略,比如负载均衡、缓存、数据库优化、微服务拆分这些。不过,可能还需要考虑用户的具体情况,比...

Java面试题: 项目开发中的有哪些成长?该如何回答

在Java面试中,当被问到“项目中的成长点”时,面试官不仅想了解你的技术能力,更希望看到你的问题解决能力、学习迭代意识以及对项目的深度思考。以下是回答的策略和示例,帮助你清晰、有说服力地展示成长点:一...

互联网大厂后端必看!Spring Boot 如何实现高并发抢券逻辑?

你有没有遇到过这样的情况?在电商大促时,系统上线了抢券活动,结果活动刚一开始,服务器就不堪重负,出现超卖、系统崩溃等问题。又或者用户疯狂点击抢券按钮,最后却被告知无券可抢,体验极差。作为互联网大厂的后...

每日一题 |10W QPS高并发限流方案设计(含真实代码)

面试场景还原面试官:“如果系统要承载10WQPS的高并发流量,你会如何设计限流方案?”你:“(稳住,我要从限流算法到分布式架构全盘分析)…”一、为什么需要限流?核心矛盾:系统资源(CPU/内存/数据...

Java面试题:服务雪崩如何解决?90%人栽了

服务雪崩是指微服务架构中,由于某个服务出现故障,导致故障在服务之间不断传递和扩散,最终造成整个系统崩溃的现象。以下是一些解决服务雪崩问题的常见方法:限流限制请求速率:通过限流算法(如令牌桶算法、漏桶算...

面试题官:高并发经验有吗,并发量多少,如何回复?

一、有实际高并发经验(建议结构)直接量化"在XX项目中,系统日活用户约XX万,核心接口峰值QPS达到XX,TPS处理能力为XX/秒。通过压力测试验证过XX并发线程下的稳定性。"技术方案...

瞬时流量高并发“保命指南”:这样做系统稳如泰山,老板跪求加薪

“系统崩了,用户骂了,年终奖飞了!”——这是多少程序员在瞬时大流量下的真实噩梦?双11秒杀、春运抢票、直播带货……每秒百万请求的冲击,你的代码扛得住吗?2025年了,为什么你的系统一遇高并发就“躺平”...

其实很多Java工程师不是能力不够,是没找到展示自己的正确姿势。

其实很多Java工程师不是能力不够,是没找到展示自己的正确姿势。比如上周有个小伙伴找我,五年经验但简历全是'参与系统设计''优化接口性能'这种空话。我就问他:你做的秒杀...

PHP技能评测(php等级考试)

公司出了一些自我评测的PHP题目,现将题目和答案记录于此,以方便记忆。1.魔术函数有哪些,分别在什么时候调用?__construct(),类的构造函数__destruct(),类的析构函数__cal...

你的简历在HR眼里是青铜还是王者?

你的简历在HR眼里是青铜还是王者?兄弟,简历投了100份没反应?面试总在第三轮被刷?别急着怀疑人生,你可能只是踩了这些"隐形求职雷"。帮3630+程序员改简历+面试指导和处理空窗期时间...

取消回复欢迎 发表评论: