数据库隔离级别的由来 及其与MVCC的关系

本贴最后更新于 3313 天前,其中的信息可能已经沧海桑田

我们都知道根据SQL92标准,关系数据库有四个隔离级别:脏读,读未提交,可重复读,可序列化。但这几个隔离级别是怎么来的?我们来扯扯把

 

如果数据库像Redis一样是单线程 串行处理所有的事务的话,我们就没有隔离级别这茬事了,或者说隔离级别都是最高的 可序列化。但是我们知道,数据库是一个磁盘IO很高的系统,尤其是用机械硬盘的时候,如果串行处理事务,那么就会导致磁盘不断寻道,处理效率低下。因此积攒一堆读写然后批量读取写入机械磁盘这会大大提高数据库的吞吐量。再加上现在CPU都这么多个核,多线程是必不可少了。

 

但多线程会带来一个问题,就是并发。你想象一下,在一个事务A里,你根据事务B未提交的记录做了一个判断并写了数据库,然后B回滚了,你会有怎样的心情~~于是乎数据库系统决定帮助你处理这个问题,提出了各种层次的隔离级别,让你读取数据的时候感觉就像只有自己在访问数据库一样。(NOSQL产品则没有这些隔离级别,甚至也没有ACID中的A-原子性,因此他们数据之间的关联关系很少,易于水平扩展,要扩展性能的话,加机器就可以了,但有得有失,用NOSQL实现复杂逻辑的时候 就要自己处理掉 事务的原子性,并发时候的脏读 等问题。)

 

数据库决定要让我们读取数据的时候感觉就像只有自己在访问数据库一样,要怎么搞呢?我们先从单线程处理所有事务的场景里开始着手,看看哪里可以改进变成并发把。

 

当两个事务里完全没有处理相同的记录的情况下,他们是天然可并发,无需额外处理。但是如果两个事务里存在相同的记录怎么办?我们分析下,对于同一条数据库记录,在不同的事务中仅存在以下几种关系:

一个事务读了,后续的另一个事务要读,简称读读

一个事务读了,后续的另一个事务要写,简称读写

一个事务写了,后续的另一个事务要读,简称写读

一个事务写了,后续的另一个事务要写,简称写写

 

先看读读,哎,好像天然可并发,怎么搞看起来都是像只有自己在访问数据库一样,棒棒哒。略过。

再看读写,第一个事务读过了,然后第二个事务要写,如果允许写的话,第一个事务不就蒙B了,这哪里是我一个人在访问数据库?!好吧,这样的话 ,根据我们程序员最直观的思维,给这条记录加个锁就好啦(行锁),每条读取的记录都要上锁。上锁后其他事务就不得读取这条记录了,除非等第一个事务完结。但这样读读关系不能并行了,于是大家都想,读读而已呀,这必须能并行呀,能提高不少性能呢。于是乎程序猿们继续发挥聪明才智,设计了读写锁~读读可并行,读写不可并行,这样就OK啦,大大提高了并行的效率。

这个做法嘛,对应的就是我们数据库隔离级别里的 可重复读。这个可重复读嘛,有一个BUG,就是所谓的 幻象读(不知道怎么能起到这么一个名字….)。这个BUG的原因如下:行锁是基于已有记录的,但如果记录不存在的话,怎么搞?如:数据库里只有2条记录,id分别为1、2;事务A第一次执行语句select * from user where id<3 有2条结果,并对这两条记录加了锁,但因没有第三条记录,所以无法加行锁。这时另外一个事务B插入了一条记录把id=3的记录插进去并提交了,那么事务A再次执行上述SQL的时候就会得到与第一次不一样的结果。看来可重复读….其实也并不可重复….

 

虽然引入了读写锁的机制后,数据库性能得到了大大的提升,但是人类追求效率的心是永无止境的,现在在上述 几个关系中,已经实现了 读读关系 并行处理了,那么其他关系能并行么?

现在有读锁和写锁,如果允许某个读锁升级成写锁的话,那么 读写关系也可以并行了,这个时候带来的负面效果是 之前一同获得读锁的事务们 再次读取这条记录的时候,有可能读到 获得写锁的事务更新的数据,于是这个隔离级别我们就称为 读已提交。

 

再继续放松限制,完全去掉读锁,也就使得 写读 也能并行了,这时候,数据库隔离级别就变成 读未提交。这时候保留的写锁,是为了保持ACID中的A,让其能回滚。

 

基于上述的实现方式,专家们定义了4种隔离级别。可见,这个隔离级别并没有其他特殊的含义,仅仅是局限于当时的技术实现形式而已。

 

在后来出现了MVCC这种基于复制记录形式的并发处理形式(具体实现自行再百度吧),指定隔离级别的专家们就蒙B了,MVCC可以做到比 可重复读更高的隔离级别(没有幻象读),且在读多些少的场景下实现比 行锁 机制里 读已提交,可重复读 更高的效率。

但由于 隔离级别在之前已经深入人心了,甚至于有些程序还利用了RC的特性来编写了程序,因此基于MVCC实现的数据库通常也会对应回四种隔离级别:可序列化(不使用MVCC),可重复读(使用MVCC,对应于SQL92里的可重复读,但不会出现幻象读),读已提交(故意减少MVCC的隔离程度,映射回RC这个隔离级别,这种实现相对于RR或许会更消耗数据库性能),以及读未提交。

大家普遍存在一个误区,隔离级别越高,数据库性能越差,这在行锁对应的数据库实现里,是正确的。但在MVCC里可就不一定了,个人认为RR的性能会比RC高,或者至少相差无几。

 

嗯~写完,OVER~

  • 数据库

    据说 99% 的性能瓶颈都在数据库。

    345 引用 • 742 回帖
  • 一致性
    10 引用 • 5 回帖
  • MVCC
    4 引用 • 4 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    210 引用 • 2040 回帖
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 2 关注
  • 微信

    腾讯公司 2011 年 1 月 21 日推出的一款手机通讯软件。用户可以通过摇一摇、搜索号码、扫描二维码等添加好友和关注公众平台,同时可以将自己看到的精彩内容分享到微信朋友圈。

    133 引用 • 796 回帖
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖
  • 旅游

    希望你我能在旅途中找到人生的下一站。

    95 引用 • 901 回帖
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 493 关注
  • H2

    H2 是一个开源的嵌入式数据库引擎,采用 Java 语言编写,不受平台的限制,同时 H2 提供了一个十分方便的 web 控制台用于操作和管理数据库内容。H2 还提供兼容模式,可以兼容一些主流的数据库,因此采用 H2 作为开发期的数据库非常方便。

    11 引用 • 54 回帖 • 668 关注
  • Visio
    1 引用 • 2 回帖 • 1 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3196 引用 • 8215 回帖
  • CloudFoundry

    Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题。

    5 引用 • 18 回帖 • 176 关注
  • 倾城之链
    23 引用 • 66 回帖 • 163 关注
  • 开源

    Open Source, Open Mind, Open Sight, Open Future!

    410 引用 • 3588 回帖
  • V2Ray
    1 引用 • 15 回帖
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 457 关注
  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    16 引用 • 236 回帖 • 267 关注
  • Gitea

    Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。

    5 引用 • 16 回帖
  • 阿里云

    阿里云是阿里巴巴集团旗下公司,是全球领先的云计算及人工智能科技公司。提供云服务器、云数据库、云安全等云计算服务,以及大数据、人工智能服务、精准定制基于场景的行业解决方案。

    84 引用 • 324 回帖
  • WebClipper

    Web Clipper 是一款浏览器剪藏扩展,它可以帮助你把网页内容剪藏到本地。

    3 引用 • 9 回帖 • 1 关注
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    34 引用 • 467 回帖 • 760 关注
  • SSL

    SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层对网络连接进行加密。

    70 引用 • 193 回帖 • 412 关注
  • Windows

    Microsoft Windows 是美国微软公司研发的一套操作系统,它问世于 1985 年,起初仅仅是 Microsoft-DOS 模拟环境,后续的系统版本由于微软不断的更新升级,不但易用,也慢慢的成为家家户户人们最喜爱的操作系统。

    227 引用 • 476 回帖
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    171 引用 • 3848 回帖
  • FlowUs

    FlowUs.息流 个人及团队的新一代生产力工具。

    让复杂的信息管理更轻松、自由、充满创意。

    1 引用 • 2 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 83 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖 • 1 关注
  • 安全

    安全永远都不是一个小问题。

    203 引用 • 818 回帖 • 1 关注
  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖