楼主: lianqihappy
1048 0

[学习分享] 你真的明白事务的隔离性吗? [推广有奖]

  • 0关注
  • 22粉丝

教授

1%

还不是VIP/贵宾

-

威望
0
论坛币
3130 个
通用积分
1.0061
学术水平
59 点
热心指数
50 点
信用等级
44 点
经验
12628 点
帖子
467
精华
3
在线时间
90 小时
注册时间
2015-3-13
最后登录
2016-8-29

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
       事务的隔离性
      Inside君发现一些用户对MySQL InnoDB的锁机制完全不能接受,因为他们大多习惯于Oracle抑或是Microsoft SQL Server等数据库的Read Committed(简称RC)事务隔离级别。但正如Jim Gray在其旷世著作《Transaction Processing: Concepts and Techniques》一书中指出的那样,大部分的数据库其实并不符合真正隔离性(true isolation)的要求。本文将结合理论和工程,来讨论事务隔离性的要求。
      面试时通常会问面试者事务ACID属性分别代表什么,甚至这已经成为网易数据库面试的标准题之一。据个人的观察,大多用户对于A、C、D属性的描述都没有太大的问题,但是Isolation这点,往往并不准确。这是因为用户通常认为数据库支持事务,那么它就应该符合ACID特性,也就符合隔离性的要求。
       但让我们看看事务处理之父Jim Gray对事务隔离性的定义:
       Isolation: Concurrently executing transactions see the stored information as if they were running serially (one after another).
      并发执行的事务能够看到存储的信息,好似事务之间是串行执行的。这里看似还是太理论,但是只要解决三个并发问题,事务间就不会有环(cycle),因此就能达到真正隔离性的要求。而这三个问题Jim Gray将其总结为Lost Update、Read Uncommitted、Unrepeatable Read:


      常见的RC隔离级别只解决了Lost Update和Read Uncommitted问题,并没有解决Unrepeatable Read问题,所以说RC并不符合隔离型的真正要求,从而在某些情况下可能会存在一些问题。这里Inside君通过MySQL数据库来举一个例子,假设表P有数据2、4、6,现在有两个事务T1、T2运行在RC事务隔离级别下,那么如果根据下面的步骤运行:


      最终表P的数据只有3一条记录,数据库日志中记录的内容是:
      INSERT INTO P  SELECT 3;
       DELETE FROM P  WHERE a <= 6;
       那么如果将上述日志传送到从机(slave)去执行,会发现从机中表P的记录数为0,也就是主从数据不一致了。而总结来看,是不是发生了并发执行的事务与串行执行的事务结果是不一样的,那么也就是说,这是不符合事务隔离性的要求。
       那么在MySQL数据库中是如何解决这个问题的呢?如果事务的隔离级别是RC,必须将日志格式设置为ROW。这样的日志格式在Inside君看来,更接近于状态机机制,从而也就解决了不一致的问题。Oracle、Microsoft SQL Server数据库都是基于页的物理逻辑复制,所以也不存在这样的问题。但是从严格理论范畴的角度看,RC不符合事务真正隔离型的要求。
       事务的隔离级别
      数据库厂商们肯定知道隔离性的真正要求,然而他们在某种程度上做了妥协,从而产生了四个不同的隔离程度(isolation degree),Degree 0、Degree 1、Degree 2、Degree 3,分别允许Lost Update、Read Uncommitted、Unrepeatable Read的问题存在,而Degree 3才是真正符合隔离性的要求。
      而ANS SQL标准没有从隔离程度进行定义,而是定义了事务的隔离级别,同时定义了不同事务隔离级别解决的三大并发问题:


       从上表可以发现隔离级别和隔离性之间有着不同的含义。那为什么各个数据库厂商更倾向于选择RC事务隔离级别呢?因为通常来说,事务隔离级别越低,所需持有锁的时间也就越短,并发性能也就越好。
       但是上述结论也不是一定的,Jim Gray在其书中也说过SERIALIZABLE的事务隔离级别在某些情况下可能会有更好的性能。在Inside君的《MySQL技术内幕:InnoDB存储引擎》一书中也有提及。那么有些认真的小伙伴就会来问,什么情况下,SERIALIZABLE事务隔离级别会有着更好的性能?这个在Inside君下篇文章中会具体说明,因为要说明白这个问题首先要解释锁的实现。
       MySQL数据库的InnoDB存储引擎是支持事务的引擎,其默认事务隔离级别为REPEATABLE READ(简称RR)。ANSI SQL标准下RR事务隔离级别是Degree 2.9999的隔离性,但是与ANSI SQL标准不同的是,InnoDB存储引擎在RR的事务隔离级别下就解决了幻读问题,从而实现Degree 3的隔离性要求,从而达到了真正隔离性的要求。对比其他数据库,要达到真正的事务隔离性要求,必须将事务隔离级别设置为SERIALIZABLE。换句话说,MySQL InnoDB的默认事务隔离级别可以理解为其他数据库的SERIABLIZABLE级别。
       然而,从严格意义上来说,InnoDB的RR事务隔离级别的实现与传统的SERIALIAZABLE事务隔离级别还是有些不一样,这导致在某些特定场景下会给用户有错愕抑或不能接受的感觉,比如唯一索引列在一个事务中允许重复值存在。不过这并不会破坏事务的一致性,只要理解InnoDB存储引擎的锁与MVCC的实现,其实有些怪异的现象都好理解。
      SNAPSHOT事务隔离级别
      经典的SERIALIAZABLE事务隔离级别采用严格的两阶段锁(strict two-phrase lock,简称:STPL)实现,这也是Jim Gray在书中提及的方法。但是由于读写都需要上锁,这样导致在大部分情况下事务的性能都不如类似RC这样的事务隔离级别。
      为了解决性能问题,最近越来越多的数据库开始支持SNAPSHOT事务隔离级别(简称SI),如Oracle、PostgreSQL、Microsoft SQL Server数据库等。SI事务隔离级别貌似解决了Dirty Read、Unrepeatable Read和Phantom Read问题。可惜的是,其依然不符合真正隔离性的要求,其存在write skew的异常问题。2008年的SIGMOD大会上,有人提出了Serializable Snapshot Isolation(SSI),从而解决了之前SI事务隔离级别存在的问题。PostgreSQL9.1版本在此论文基础上实现了SSI事务隔离级别并做了相应的优化。此外,在2012年的VLDB大会上PostgreSQL发布了相应的论文,有兴趣的读者可以继续研究。
       基于快照的事务隔离级别(不论SI还是SSI)性能较之经典的SERIALIZABLE事务隔离级别提升非常多,但其存在两个问题不容忽视。一是其会导致“错误”的回滚,因为其策略就是保证正确,虽然有时可能会误杀一些没有问题的事务。二是对于大事务的支持需要额外的内存保证,如果修改的数据量特别大,那么这可能会导致内存溢出的问题发生。但不论怎么说,SSI可能都是未来的一个默认事务隔离级别发展的方向。期待MySQL数据库也能尽快支持
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Transactions Transaction information Processing Techniques Microsoft Oracle 数据库 网易 隔离

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-4-27 21:16