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

精通Java事务编程(3)-弱隔离级别之快照隔离和可重复读

mhr18 2024-09-29 14:02 25 浏览 0 评论

表面看,RC已满足事务所需的一切特征:支持中止(原子性),防止读取不完整的事务结果,并防止并发写的混乱。这点很关键!为我们的开发省去一大堆麻烦。

但此隔离级别仍有很多地方可能产生并发错误。如图-6说明RC可能发生的问题。

Alice在银行有1000存款,分为两个账户,每个500。现有一笔转账交易从账户1转移100到账户2。若她在提交转账请求后、银行DB系统执行转账的过程中间,查看两个账户的余额,她可能看到账号2在收到转账前的余额(500),和账户1在完成转账之后的余额(400)。对Alice,貌似她的账户总共只有900,100消失!

这种异常就是不可重复读(nonrepeatable read)或读倾斜(read skew):若Alice在交易结束时再读取账户1的余额,将看到和她之前的查询看到的不同的值(600)。RC下,不可重复读被认为是可接受的:Alice 看到的帐户余额的确都是账户当时的最新值。

术语 倾斜(skew) 这词有些滥用:以前使用它是因为热点的不平衡工作量,而在此意味着异常时序。

Alice案例不是长期持续的问题,几s后当她刷新银行页面,可能就看到一致的帐户余额。但有的场景不能容忍这种暂时的不一致:

  • 备份
  • 备份需复制整个DB,大型DB可能需数h。备份进程运行时,DB仍会接受写。因此镜像备份里可能包含一些旧版本数据和一些新版本数据。从这样的备份中恢复,最终就会导致永久性的不一致(如那些消失的存款)
  • 分析查询和完整性检查
  • 有时查询会扫描几乎大半个DB。这类查询在分析中很常见,也可能是定期的数据完整性检查(监视数据损坏情况)。若这些查询在不同时间点观察DB,则可能会返回无意义的结果

【快照隔离】是这类问题最常见解决方案。每个事务都从DB的一致性快照(consistent snapshot)中读取,即事务一开始所看到是最近提交的数据。即使这些数据随后被另一个事务更改,每个事务也只能看到该特定时间点的旧数据。

快照隔离对长时间运行的只读查询(如备份和分析)很有用。若数据在查询执行的同时变化,则很难理解查询结果的物理含义。而若查询的是DB在某特定时间点冻结时的一致性快照,则查询结果含义明确。

快照隔离很流行:PostgreSQL、InnoDB引擎的MySQL、Oracle、SQL Server 等都支持。

实现快照隔离

类似RC,快照隔离的实现通常使用写锁防止脏写,正在进行写入的事务会阻止另一个事务修改同一个对象。但读取则不无需加锁。性能角度,快照隔离的关键点:读不会阻塞写,写不会阻塞读。这允许DB可在正常处理写入的同时,在一致性快照上执行长时间的只读查询,且两者之间没有任何锁竞争。

为实现快照隔离,DB用类似图-4防脏读但却更通用的机制。考虑到多个正在进行的事务可能在不同时间点查看数据库状态,所以DB保留对象的多个不同的提交版本,所以这种技术也称为多版本并发控制(MVCC, multi-version concurrency control)。

若只是为提供RC,而非完整的快照隔离,则只保留对象的两个版本即可:

  • 已提交的旧版本
  • 尚未提交的新版本

所以,支持快照隔离的存储引擎一般也直接使用MVCC实现RC。典型做法:

  • 在RC下,为每个不同的查询单独创建一个快照
  • 而快照隔离则是对整个事务使用相同的一个快照。

图-7说明如何在 PostgreSQL 中实现基于 MVCC 的快照隔离(其他实现基本类似)。当事务开始时,首先赋予一个唯一、单调递增 1 的事务ID(txid)。每当事务向DB写入新内容,所写入的数据都会被标记写入者的事务ID。

表中的每行都有个 created_by 字段,其中包含将该行插入到表中的的事务ID。都有个 deleted_by 字段,最初是空的。如某事务删除了一行,那么该行实际上并未从数据库中删除,而是通过将 deleted_by 字段设置为请求删除的事务的 ID 来标记为删除。稍后时间,当确定没有事务可以再访问已删除的数据时,数据库中的gc过程会将所有带有删除标记的行移除,并释放其空间。

这样的一笔UPDATE 操作在内部会被转换为一个 DELETE 和一个 INSERT 。图-7中,事务13从账户2扣100,将余额从 500改为400。account 表会出现两条账户2的记录:

  • 余额为500的行被标记为被事务13删除
  • 余额为400的行由事务13创建

一致性快照的可见性规则

当事务读DB时,通过事务ID可决定哪些对象可见,哪些不可见。要想对上层应用维护好快照的一致性,需仔细定义可见性规则:

  1. 每个事务开始时,DB列出当时所有当时还在进行中(即尚未提交或中止)的其它事务,然后忽略这些事务完成的部分写入(尽管之后可能会被提交),即不可见
  2. 所有中止事务所做的任何修改全部不可见
  3. 较晚事务ID(即晚于当前事务开始)所做的任何修改不可见,而不管这些事务是否已完成提交
  4. 此外的所有其他写入都对应用查询可见

以上规则适用于创建、删除操作。图-7中,当事务12从账户2读时,会看到500余额,因为500余额的删除是由事务13完成的(根据规则 3,事务12看不到事务13执行的删除),同理400美元记录的创建也不可见。

即若如下两个条件都成立,则该数据对象对事务可见:

  • 读事务开始的时刻,创建该对象的事务已完成提交
  • 对象未被标记为删除或即使被标记为删除了,但删除事务在当前读事务开始时还没有完成提交

长时间运行的事务可能会使用快照很长时间,其他事务角度,它可能在持续访问正在被覆盖或删除的内容。由于没有就地更新,而是每次修改总创建一个新版本,因此DB可以以较小运行代价来维护一致性快照。

索引和快照隔离

多版本DB如何支持索引?一种方案是索引直接指向对象所有版本,并且需要索引查询过滤掉对当前事务不可见的对象版本。当后台的GC进程决定删除某个事务不可见的旧对象版本时,相应索引条目也随之删除。

实践中,许多细节决定了多版本并发控制的性能,如:

  • 可将同一对象的不同版本放入同一内存页,PostgreSQL如此优化可避免更新索引
  • CouchDB、Datomic 和 LMDB使用另一种方案。虽然也使用B树,但采用追加/写时复制(append-only/copy-on-write),当需要更新时,不会修改现有的页,而总是创建一个新的修改副本,拷贝必要的内容,然后让父结点或递归向上直到树root都指向新创建的结点。那些不受更新影响的页面都无需复制,保持不变并被父结点所指向。

这种使用追加的B树,每个写入事务(或一批事务)都会创建一个新的B 树,当创建时,从该特定树根生长的树就是该时刻DB的一致性快照。这时就没必要根据事务ID再去过滤对象,每个写入都会修改现有的B树,因为之后的 询可以直接作用于特定快照B-tree(有利于查询性能)。采用这种方案依然需要后台进程来执行压缩和GC。

可重复读与命名混淆

快照隔离对只读事务特别有效。但DB实现用不同名字来称呼:

  • Oracle 中称为可串行化(Serializable)
  • PostgreSQL 和 MySQL 中称为可重复读(repeatable read)

命名混淆原因是SQL标准未定义快照隔离,而仍是基于System R 1975年定义的隔离级别,那时还没快照隔离。而定义了 可重复读,表面看起来接近快照隔离。 所以PostgreSQL 和 MySQL 称快照隔离级别为可重复读(repeatable read),这符合标准要求。

但SQL标准对隔离级别的定义存在缺陷的,模糊,不精确,做不到独立于实现。有几个DB实现了可重复读,但它们实际提供的保证差异很大。IBM DB2 使用 “可重复读” 实现可串行化级别的隔离。

所以导致结果,无人真正知道可重复读到底啥意思。

Footnotes

  1. 事务ID是32位整数,所以大约在40亿次事务后溢出。 PostgreSQL 的 Vacuum 过程会清理老旧的事务 ID,确保事务 ID 溢出(回卷)不会影响到数据。 ?


作者:JavaEdge在掘金
链接:https://juejin.cn/post/7125794799461859335

相关推荐

jdk17安装和配置环境变量(jdk安装步骤环境变量配置)

简单介绍JDK17是Java的一个长期支持(LTS)版本,于2021年9月发布。作为LTS版本,它将获得Oracle的长期支持,这意味着会获得安全更新和错误修复,直到2...

jdk8安装和配置环境变量(jdk8配置环境变量win10)

简单介绍JDK8是Java开发工具包的一个重大版本,于2014年3月发布。它引入了许多重要的新特性,极大地改进了Java编程的体验,并提高了代码的效率和可读性。总结JDK8是一...

Java开发环境的准备流程!(java开发环境的准备流程有哪些)

准备开发环境工欲善其事,必先利其器。在学习本书的技术内容之前,应先将开发环境搭建好。本书所涉及的基础环境将在本章准备,包括JDK、IntelliJIDEA和Maven。如果读者对这些环境较为熟悉,可...

skywalking-全链路跟踪(链路追踪sleuth)

一、概述1、skywalking简介SkyWalking是一款广受欢迎的国产APM(ApplicationPerformanceMonitoring,应用性能监控)产品,主要针对微服务、Clou...

Oracle项目管理系统之成本状态跟踪

卷首语成本费用管理模块功能分为公司级、项目级两个层级,其中公司级功能包括概预算管理、概预算定额管理、预算模板管理,以及控制估算管理等功能。费用与成本成本费用管理主要是为了合理利用资金资源,控制企业的成...

从入门到精通,Java最全学习路线(java自学路线)

最近好多小伙伴询问,该如何学习java?那些视频适合零基础学习呢?大多数都是一些刚入门的新手,还不了解这个行业,也不知道从何学起,开始的时候非常迷茫,在这给大家整理出一些学习路线。Java学习路线在这...

SPARC M7最新技术 甲骨文首度在台发表

甲骨文首度在台发表SPARCM7最新技术,宣布推出全新SPARC系统產品系列,採用革命性的32内核、256执行绪SPARCM7微处理器。这套SPARC系统提供:先进的入侵防护和加密的Securit...

轻量化的企业级OLAP方案2(轻量化ar)

上一篇文章讲了一个轻量化的企业级OLAP方案,这一篇文章继续介绍另外一个方案。方案2:Greenplum1Greenplum介绍1.1Greenplum概念Greenplum数据库是一种基于Po...

时序数据库在水电站领域的应用(时序数据库优缺点)

大家好,上期经过了王宏志教授对数据库前沿领域的介绍,不知道小伙伴们是否对数据库领域有了更深的认识呢,本期让我们回归时序数据库,再来聊一聊时序数据库在水电站领域的应用。本文仅代表个人观点,如有偏颇之处,...

数据库SQL引擎比较(数据库引擎有哪些,有什么区别)

数据库SQL引擎的典型工作机制及详细分析如下,涵盖查询处理全流程中的核心机制与实际案例:一、SQL引擎核心处理流程1.解析与校验阶段词法/语法解析:SQL语句被拆解为Token序列,构建...

Ubuntu系统密码(root密码)的修改方法

本文介绍在Linux系统的Ubuntu电脑中,修改账户用户密码(同时也修改了root用户密码)的方法。首先,如果此时处于登录页面(也就是意识到自己忘记密码的那个页面),就先点击右上角的关闭按钮...

TablePlus:一个跨平台的数据库管理工具

TablePlus是一款现代化的跨平台(Window、Linux、macOS、iOS)数据库管理工具,提供直观的界面和强大的功能,可以帮助用户轻松管理和操作数据库。TablePlus免费版可以永久...

云满足用户对通过单一视图了解整体运营和数据的需求

ZD至顶网软件频道消息:云在简化IT和业务的同时也带来了新问题,这很有趣,不是吗?毫无疑问,云大幅降低了企业运行基础设施和应用的复杂性和成本;但您仍然面临一个老生常谈的问题——孤岛,只不过这次是在云...

SQL_TOP(显示数据条数)(sqlserver显示查询的行数)

(8)SELECT(9)DISTINCT(11)<topNum><selectlist>(1)FROM[left_table](3)<join_type>...

php搭建小型部门网站(php构建网站)

熟悉前端html,js,css,后端熟悉php,python,java只能称得上一般,还有很多坑待踩。鉴于所学很杂,决定利用对业务的熟悉来搞一个部门网站来简化大家的工作流程。初步设计方案后端用p...

取消回复欢迎 发表评论: