热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数据库事务_数据库事务隔离标准分析

本文由编程笔记#小编为大家整理,主要介绍了数据库事务隔离标准分析相关的知识,希望对你有一定的参考价值。1概述与背景这是数
本文由编程笔记#小编为大家整理,主要介绍了数据库事务隔离标准分析相关的知识,希望对你有一定的参考价值。



1 概述与背景

这是数据库事务原理和工程实践系列文章的第一篇,本文主要在Jim Gray的论文基础上分析关系数据库的事务隔离级别标准和不同隔离级别情况下的行为。第2节主要讨论ANSI标准的下的隔离级别,第3节主要讨论基于悲观锁实现的事务隔离级别,第4节主要讨论基于多版本技术的事务隔离,最后总结排序本文讨论到的各个隔离级别。

ACID是关系数据库的一组重要特性,其中Isolation(隔离性)描述了数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发时由于交错执行而导致数据的不一致。在最极端的情况下,数据库完全串行化执行每一个事务,所有事务之间遵守全序关系,在这种情况下,不存在并发事务间的隔离问题,但是在实际工程实践中,处于对数据库性能吞吐量的考虑,允许多个事务之间按照一定的规则,打破串行话的全序关系,ANSI SQL Isolation Levels即规定了这种“规则”,通过将隔离性划分为4个级别,来换取多层级的事务间并发能力(即数据库的吞吐能力)。

注,本文内容融入了作者个人的理解,并没有严格遵守<A Critique of ANSI SQL Isolation Levels>原文的内容;其中cursor stability隔离级别将在后续文章中讨论,快照隔离级别与ANSI标准异象的比较也有所不同。


2 ANSI事务隔离级别

ANSI SQL-92标准(http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt)将数据库并发事务间的隔离性行为划分为3种"异象(phenomena)",从低到高的自然语言定义依次为:



  1. P1 脏读 ("Dirty read"): SQL-transaction T1 modifies a row. SQL- transaction T2 then reads that row before T1 performs a COMMIT. If T1 then performs a ROLLBACK, T2 will have read a row that was never committed and that may thus be considered to have never existed. 


  2. P2 不可重复读 ("Non-repeatable read"): SQL-transaction T1 reads a row. SQL- transaction T2 then modifies or deletes that row and performs a COMMIT. If T1 then attempts to reread the row, it may receive the modified value or discover that the row has been deleted. 


  3. P3 幻读 ("Phantom"): SQL-transaction T1 reads the set of rows N that satisfy some . SQL-transaction T2 then executes SQL-statements that generate one or more rows that satisfy the used by SQL-transaction T1. If SQL-transaction T1 then repeats the initial read with the same , it obtains a different collection of rows.


通过依次禁止这三种异象,ANSI确定了4种标准隔离级别,如下表所示:






































级别 P1(脏读) P2(不可重复读) P3(幻读)
Read Uncommitted 允许 允许 允许
Read Committed 禁止 允许 允许
Repeatable Read 禁止
禁止
允许
(Anomaly) Serializable 禁止
禁止
禁止
Note: The exclusion of these penomena or SQL-transactions executing at isolation level SERIALIZABLE is a consequence of the requirement that such transactions be serializable.

如标准文档所述,禁止了P1/P2/P3异象的事务即满足Serializable级别,但矛盾的是,标准文档中对Serializable又做了如下说明:








The execution of concurrent SQL-transactions at isolation level SERIALIZABLE is guaranteed to be serializable. A serializable execution is defined to be an execution of the operations of concurrently executing SQL-transactions that produces the same effect as some serial execution of those same SQL-transactions

它要求多个并发事务执行的效果与某种串行化执行的效果一致,但是仅仅禁止P1/P2/P3异象,并不一定能够保证“serial execution”的效果,因此论文中将ANSI Serializable称为Anomaly Serializable。


P1/P2/P3的形式化描述

根据标准文档的定义,可以将这三种异象使用形式化语言描述如下,称为A1/A2/A3(其中w1[x]表示事务1写入记录x,r1表示事务1读取记录x,c1表示事务1提交,a1表示事务1回滚,r1[P]表示事务1按照谓词P的条件读取若干条记录,w1[y in P]表示事务1写入记录y满足谓词P的条件):




  • A1 脏读:w1[x] ... r2[x] ... (a1 and c2 in any order)


  • A2 不可重复读:r1[x] ... w2[x] ... c2 ... r1[x] ... c1


  • A3 幻读:r1[P] ... w2[y in P] ... c2 ... r1[P] ... c1




上述A1/A2/A3形式化描述,根据标准定义的P1/P2/P3异象的自然语言描述转化而来,但是ANSI标准定义的异象只针对了单个记录或谓词描述,对于多条记录需满足业务一致性的场景并未能覆盖(比如两个账户间转账要求余额总和不变),举例如下:




  • H1:r1[x=50]w1[x=10] r2[x=10]r2[y=50] c2 r1[y=50]w1[y=90] c1



    • 事务1执行账户x向账户y转账40,事务2读取到了进行到了一半的事务1(Read Uncommitted),破坏了余额总和的一致性


    • 因为事务1并未回滚,H1的行为并不符合A1的形式化定义



  • H2:r1[x=50] r2[x=50]w2[x=10]r2[y=50]w2[y=90] c2 r1[y=90] c1



    • 事务2执行账户x向账户y转账40,事务1在事务2提交前后读取到了破坏余额总和一致性的数据(Unrepeatable Read)


    • 因为事务1并未重复读取记录x,H2的行为并不符合A2的形式化定义



  • H3:r1[P] w2[insert y to P] r2[z] w2[z] c2 r1[z] c1



    • 事务2增加新雇员并更新雇员总数z,事务1在事务2提交前后读取到了破坏雇员列表与雇员总数的一致性的数据(Phantom)


    • 因为事务1并未重复读取谓词P指定的数据集合,H3的行为并不符合A3的形式化定义





因为要增强对上述H1/H2/H3异象的约束,论文将A1/A2/A3的形式化描述称为“狭义的描述(strict interpretations)”,然后增加了“广义的描述(broad interpretation)”,去除了strict interpretations中对事务提交、回滚和数据读取范围的约束,只保留事务之间读写的时序关系,即事务之间只要包含如下时序的操作,即可能产生包含H1/H2/H3在内的异象,如下:




  • P1 脏读:w1[x] ... r2[x] ... ((c1 or a1) and (c2 or a2) in any order)


  • P2 不可重复读:r1[x] ... w2[x] ... ((c1 or a1) and (c2 or a2) in any order)


  • P3 幻读:r1[P] ... w2[y in P] ... ((c1 or a1) and (c2 or a2) in any order)


在上述形式化描述下,禁止P1即可禁止H1,禁止P1/P2即可禁止H2,禁止P1/P2/P3即可禁止H3。至此,ANSI标准隔离级别定义的三种异象,可以被扩展为适用范围更广的的P1/P2/P3的形式化定义,这种隔离级别定义被论文称之为“phenomena-based”,即基于“异象”的隔离级别定义。



3 基于锁的事务隔离

在上一节的讨论中,P1/P2/P3这三种形式化定义指出了三个不同级别的异象,但是并没有与实际的工程实践相关联,在本小节中,我们将介绍基于锁(lock base)的事务隔离实现,并且将不同的加锁行为与上述三种异象关联起来讨论。

在讨论加锁行为之前,需要定义如下几种读写和锁的操作:



  • Predicate lock 谓词锁(gap锁):Locks on all data items satisfying the search condition


  • Well-formed Writes 合法write:Requests a Write(Exclusive) lock on each data item or predicate before writing


  • Well-formed Reads 合法read:Requests a Read(share) lock on each data item or predicate before reading


  • Long duration locks 长周期锁:Locks are held until after the transaction commits or aborts


  • Shord duration locks 短周期锁:Locks are released immediately after the action completes


通过组合上述读写锁操作,我们能够构建不同级别的事务隔离标准。因为“No Well-formed Writes”或“Short duration write locks”的保护等级可能造成dirty write,它的约束已经低到难以找到实际应用场景,我们将其忽略,因此所有写入操作都使用“Well-formed Writes, Long duration Write locks”,通过对读取操作应用不同的保护等级,得到4种隔离级别,使用locking前缀与ANSI隔离级别区分,如下表所示:































Read Lock Write Lock
Locking
Read Uncommited

none required

Well-formed Writes,

Long duration Write locks

Locking
Read Commited
Well-formed Reads,
Short duration read lock

Well-formed Writes,

Long duration Write locks

Locking
Repeatable Read
Well-formed Reads,
Long duration data-item Read locks,
Short duration Read Predicate locks

Well-formed Writes

Long duration Write locks

Locking
Serializable
Well-formed Reads,
Long duration Read locks

Well-formed Writes

Long duration Write locks

将locking标记的四种隔离级别与ANSI隔离级别对比:



  • Well-formed Reads, Short duration read lock 禁止了 P1发生,r2[x]将被读锁阻塞,直到事务1提交或回滚


  • Well-formed Reads, Long duration data-item Read locks, Short duration Read Predicate locks 禁止了P2发生,w2[x]将被写锁阻塞,直到事务1提交或回滚



    • 其中Short duration Read Predicate locks的作用论文中并没有说明,实际上它保护了r[P]的一致性,保证r[P]读取到的多行数据是一个“well-formed history”



  • Well-formed Reads, Long duration Read locks 禁止了P3发生,w2[y in P]将被谓词写锁阻塞,直到事务1提交或回滚


如上所述,Lock Base的隔离级别能够完全覆盖ANSI基于异象的隔离级别约束,论文中也称“phenomena-based”是“disguised versions of locking”。


4 基于快照的事务隔离

对于基于锁实现事务隔离的数据库,读写、写写事务之间也可能因为锁冲突而被阻塞,数据库的整体吞吐能力受到比较大的限制,特别是在目前多核的CPU条件下,难以充分发挥计算能力。因此现代关系型数据库和NewSQL,比如mysql/Oracle/PostgreSQL/OceanBase/TiDB等,都使用多版本并发控制(mvcc)技术,来实现事务隔离,它的核心设计思想是,为数据的每次修改保存一个用时间戳标记的版本,数据读取不需要加锁,而是在读取事务开始的时候获取当前时间戳(snapshot),对于每条数据,将版本号小于snapshot的最大已提交版本的内容作为读取结果返回。

Snapshot Isolation保证只读事务与读写事务相互不阻塞,只读事务通过读取合法的历史快照,保证了读取到的数据的一致性,我们在快照隔离下与A1/A2/A3逐个对比分析:



  • P1描述的w1[x] ... r2[x] ...操作时序不可能出现,因为在快照隔离下,实际的操作时序为w1[x] ... r2[last version of x] ...,因此可知快照隔离禁止P1


  • P2描述的r1[x] ... w2[x] ... 它实际的操作时序为r1[x] ... w2[new version of x] ...,可以知道快照隔离也禁止了P2。至此,我们可以确定快照隔离的效果至少大于Read Committed


  • P3描述的r1[P] ... w2[y in P] ... 它实际的操作时序为r1[P] ... w2[new version of y in P] ...,可以知道快照隔离也禁止了P3,达到了第2小节中ANSI的Anomaly Serializable级别



但是,从上一小节基于锁的隔离级别定义来分析,快照隔离的安全级别可能并没有那么高,我们来看如下两种异象的形式化描述:



  • A5A Read Skew: r1[x]...w2[x]...w2[y]...c2...r1[y]...(c1 or a1)


  • A5B Writer Skew: r1[x]...r2[y]...w1[y]...w2[x]...(c1 and c2 occur)



    • 扩展的Write Skew(并非来自原文):r1[P]...r2[P]...w1[x]...w2[y]...(c1 and c2 occur)



快照隔离性高于Read Committed:第一,考虑到快照隔离读已提交的数据版本的特性,禁止了P1,因此保证至少不低于Read Committed。第二,A5A的Read Skew异象符合P2的定义,并且从一致性的角度分析,事务1对x和y的读取的两个值不在线性的历史中,可能会违背某种外部约束(比如保证x+y的和为一个常量),因此Read Committed隔离级别下允许A5A Read Skew异象。总和以上两点,我们可以得出结论,快照隔离性高于Read Committed。

快照隔离性与Repeatable Read不相容:考虑到快照隔离能够保证读取到的数据在一个一致的历史快照上,禁止了P1/P2/P3,因此保证不低于ANSI的Anomaly Serializable级别;但是,另一方面,经典的快照隔离对于多写冲突是基于First- committer-wins的处理方式,依赖冲突的事务间至少修改同一条记录(现代快照隔离有更优的SSI,我们将在后续的文章中介绍)无法避免上述A5B Write Skew的两种异象,而基于锁事项的Repeatable Read级别却可以禁止A5B。快照隔离与Repeatable Read双方禁止的异象,有可能在对方出现,因此他们的隔离性无法相比较。


5 总结

从前面几个小节的隔离性分析来看,我们可以得到如下几种隔离级别的关系:








Read Uncommitted < Read Committed < (Repeatable Read >< Snapshot) < Serializable

本文首先介绍了ANSI基于“异象”的隔离级别标准,并分析了其狭义和广义的描述;然后介绍了基于锁的隔离级别标准,与ANSI隔离级别进行了比较;最后分析快照隔离级别,在ANSI隔离级别标准基础上,提出了两种新的“异象”,得出快照隔离在几种标准隔离级别特性中的位置。



推荐阅读
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 使用种子数据在Asp.NET Core 3.0 Web API迁移过程中写入数据库的详细步骤
    本文详细阐述了如何在Asp.NET Core 3.0 Web API的迁移过程中利用种子数据将信息写入数据库的具体步骤。对于开发人员而言,掌握这一技术能够显著提高数据初始化的效率和准确性。文章不仅提供了详细的代码示例,还深入解析了每个步骤背后的原理,帮助读者更好地理解和应用这一方法。 ... [详细]
  • R语言中向量(Vector)数据类型的元素索引与访问:利用中括号[]和赋值操作符在向量末尾追加数据以扩展其长度
    在R语言中,向量(Vector)数据类型的元素可以通过中括号 `[]` 进行索引和访问。此外,利用中括号和赋值操作符,可以在向量的末尾追加新数据,从而动态地扩展向量的长度。这种方法不仅简洁高效,还能灵活地管理向量中的数据。 ... [详细]
  • 在Cisco IOS XR系统中,存在提供服务的服务器和使用这些服务的客户端。本文深入探讨了进程与线程状态转换机制,分析了其在系统性能优化中的关键作用,并提出了改进措施,以提高系统的响应速度和资源利用率。通过详细研究状态转换的各个环节,本文为开发人员和系统管理员提供了实用的指导,旨在提升整体系统效率和稳定性。 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
  • 本文详细介绍了在CentOS 6.5 64位系统上使用阿里云ECS服务器搭建LAMP环境的具体步骤。首先,通过PuTTY工具实现远程连接至服务器。接着,检查当前系统的磁盘空间使用情况,确保有足够的空间进行后续操作,可使用 `df` 命令进行查看。此外,文章还涵盖了安装和配置Apache、MySQL和PHP的相关步骤,以及常见问题的解决方法,帮助用户顺利完成LAMP环境的搭建。 ... [详细]
  • Amoeba 通过优化 MySQL 的读写分离功能显著提升了数据库性能。作为一款基于 MySQL 协议的代理工具,Amoeba 能够高效地处理应用程序的请求,并根据预设的规则将 SQL 请求智能地分配到不同的数据库实例,从而实现负载均衡和高可用性。该方案不仅提高了系统的并发处理能力,还有效减少了主数据库的负担,确保了数据的一致性和可靠性。 ... [详细]
  • NOIP2000的单词接龙问题与常见的成语接龙游戏有异曲同工之妙。题目要求在给定的一组单词中,从指定的起始字母开始,构建最长的“单词链”。每个单词在链中最多可出现两次。本文将详细解析该题目的解法,并分享学习过程中的心得体会。 ... [详细]
  • 本指南详细介绍了在Linux环境中高效连接MySQL数据库的方法。用户可以通过安装并使用`mysql`客户端工具来实现本地连接,具体命令为:`mysql -u 用户名 -p 密码 -h 主机`。例如,使用管理员账户连接本地MySQL服务器的命令为:`mysql -u root -p pass`。此外,还提供了多种配置优化建议,以确保连接过程更加稳定和高效。 ... [详细]
  • MyISAM和InnoDB是MySQL中最为广泛使用的两种存储引擎,每种引擎都有其独特的优势和适用场景。MyISAM引擎以其简单的结构和高效的读取速度著称,适用于以读操作为主、对事务支持要求不高的应用。而InnoDB引擎则以其强大的事务处理能力和行级锁定机制,在需要高并发写操作和数据完整性的场景下表现出色。选择合适的存储引擎应综合考虑业务需求、性能要求和数据一致性等因素。 ... [详细]
  • 阿里云MySQL与Oracle数据库的主从复制技术详解 ... [详细]
  • 技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告
    技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告 ... [详细]
  • Java环境中Selenium Chrome驱动在大规模Web应用扩展时的性能限制分析 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • 在C#中开发MP3播放器时,我正在考虑如何高效存储元数据以便快速检索。选择合适的数据结构,如字典或数组,对于优化性能至关重要。字典能够提供快速的键值对查找,而数组则在连续存储和遍历方面表现优异。根据具体需求,合理选择数据结构将显著提升应用的响应速度和用户体验。 ... [详细]
author-avatar
刘家大宝688
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有