重要要点

  • 仅凭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是不够的。您确实需要知道它支持什么隔离级别以及在什么情况下。

本文 http://jiagoushi.pro/node/918
讨论:请加入知识星球【首席架构师圈】或者加微信小号【jiagoushi_pro】或者加QQ群【11107777】
公众号 【jiagoushipro】
【超级架构师】
精彩图文详解架构方法论,架构实践,技术原理,技术趋势。
我们在等你,赶快扫描关注吧。
微信小号 【cea_csa_cto】
50000人社区,讨论:企业架构,云计算,大数据,数据科学,物联网,人工智能,安全,全栈开发,DevOps,数字化.

QQ群 【11107767】深度交流企业架构,业务架构,应用架构,数据架构,技术架构,集成架构,安全架构。以及大数据,云计算,物联网,人工智能等各种新兴技术。
加QQ群,有珍贵的报告和干货资料分享。

视频号 【超级架构师】
1分钟快速了解架构相关的基本概念,模型,方法,经验。
每天1分钟,架构心中熟。

知识星球 向大咖提问,近距离接触,或者获得私密资料分享。 知识星球【首席架构师圈】
微信圈子 志趣相投的同好交流。 微信圈子【首席架构师圈】
喜马拉雅 路上或者车上了解最新黑科技资讯,架构心得。 【智能时刻,架构君和你聊黑科技】
知识星球 认识更多朋友,职场和技术闲聊。 知识星球【职场和技术】
微博 【智能时刻】 智能时刻
哔哩哔哩 【超级架构师】
抖音 【cea_csa_cto】超级架构师
快手 【cea_csa_cto】超级架构师
小红书 【cea_csa_cto】超级架构师 首席架构师智库

谢谢大家关注,转发,点赞和点在看。

「数据库架构」三分钟搞懂事务隔离级别和脏读相关推荐

  1. mysql 隔离级别 快照_「数据库架构」三分钟搞懂事务隔离级别和脏读

    重要要点 仅凭ACID或非ACID来思考,还需要知道数据库支持的隔离级别. 标榜为"最终一致"的某些数据库可能返回与任何时间点不一致的结果. 一些数据库提供的隔离级别比您要求的更高 ...

  2. 一文带你轻松搞懂事务隔离级别(图文详解)

    本文由 SnailClimb 和读者 BugSpeak 共同完成. 事务隔离级别(图文详解) 什么是事务? 事务是逻辑上的一组操作,要么都执行,要么都不执行. 事务最经典也经常被拿出来说例子就是转账了 ...

  3. java 一个大事务下的新增、修改、查询_一文带你轻松搞懂事务隔离级别(图文详解)...

    点击上方"linkoffer", 选择关注公众号高薪职位第一时间送达 本文由 SnailClimb 和读者 BugSpeak 共同完成. 事务隔离级别(图文详解) 什么是事务? 事 ...

  4. 8000字 | 32 张图 | 一文搞懂事务+隔离级别+阻塞+死锁

    来源 | 悟空聊架构(ID:PassJava666) 本篇主要内容如下: 本篇主要内容 一.事务 1.1 什么是事务 为单个工作单元而执行的一系列操作.如查询.修改数据.修改数据定义. 1.2 语法 ...

  5. mysql讲事物写到数据库_CookBook/1-MySQL数据库读写锁示例详解、事务隔离级别示例详解.md at master · Byron4j/CookBook · GitHub...

    MySQL数据库读写锁示例详解.事务隔离级别示例详解 锁 性能分:乐观(比如使用version字段比对,无需等待).悲观(需要等待其他事务) 乐观锁,如它的名字那样,总是认为别人不会去修改,只有在提交 ...

  6. 数据库事务隔离级别及脏读、不可重复读、幻读的理解

      开篇声明,由于两位大佬排版不够美观,然后又发现一些歧义,因此我集大佬之所长,精心整理并加以完善,可放心阅读. http://blog.csdn.net/yuxin6866/article/deta ...

  7. 【领域驱动设计】三分钟搞懂领域驱动设计

    今天的企业应用程序无疑是复杂的,并依赖一些专门技术(持久性,AJAX,Web服务等)来完成它们的工作.作为开发人员,我们倾向于关注这些技术细节是可以理解的.但事实是,一个不能解决业务需求的系统对任何人 ...

  8. oracle同步数据adg_[adg数据库同步机制]三分钟读懂Oracle数据库容灾架之DataGuard

    在线QQ客服:1922638 专业的SQL Server.MySQL数据库同步软件 Oracle数据库目前依然处于商用数据库的霸主地位. 运行在Oracle数据库上的核心业务及核心数据的安全性尤为重要 ...

  9. 「数据架构」5分钟学会数据流程图:客户服务系统示例

    数据流图(DFD)提供了系统内信息流(即数据流)的可视化表示.通过创建一个数据流图,您可以告诉参与系统流程的人员所提供和交付的信息.完成流程所需的信息以及需要存储和访问的信息.数据流图在软件工程中得到 ...

最新文章

  1. s-sed(stream editor) 文本填充和编辑 基本使用
  2. 使用tab键分割的文章能快速转换成表格。( )_word排版技巧:活用Enter键提高工作效率...
  3. [No000035]操作系统Operating System之OS Interface操作系统接口
  4. 关于iframe中session 失效问题
  5. array_uniquee php_【性能为王】从PHP源码剖析array_keys和array_unique
  6. 问题解决:错误:unable to connect to node rabbit@localhost: nodedown
  7. JSON 字符串 与 java 对象的转换
  8. 阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第1节 基础加强_3_Junit_使用步骤...
  9. 数据库中的二维表—巧借Excel
  10. 【小程序】用canvas 实现一个简易的移动端名片可编辑小程序
  11. 【Nav2中文网】五、普通教程(九)Groot与行为树互动
  12. Matlab读取二进制数据文件
  13. wincc实现手机APP远程监控
  14. 全国计算机一级考试用什么版本,计算机等级考试用的是那个版本的office?
  15. 【重磅】全行业事理图谱V3.0正式发布:基于实证的由因求果、由果溯因,因果路径发现
  16. Echarts 折线图 渐变色 不堆叠
  17. xuexi.cn-app处理记录
  18. 人生苦短我爱python英文_人生苦短,我爱Python001——Python简介
  19. 如何做好软件自动更新
  20. 开发必备windows效率工具软件强力推荐

热门文章

  1. tf.logging.set_verbosity
  2. 【华为机试真题Python】VLAN资源池
  3. 【应用】博图SCL语言之抢答器应用
  4. win11取消右键菜单折叠
  5. 怎么用Python在Mac上关机
  6. 微信小程序的演出门票管理系统-票务转票系统
  7. R语言开发工具RStudio的安装
  8. UBUTNU 18.04下的USRP N310连接
  9. 使用北鲲云在AWS上运行基因分析HPC任务
  10. 如何读取 CSV文件