码迷,mamicode.com
首页 > 其他好文 > 详细

[转载] 你真的明白事务的隔离性吗?

时间:2015-11-09 09:21:44      阅读:393      评论:0      收藏:0      [点我收藏+]

标签:

原文: http://mp.weixin.qq.com/s?__biz=MjM5MjIxNDA4NA==&mid=400262409&idx=1&sn=827bdcde075ef2f96c82a3f11fa422d4&scene=0&key=b410d3164f5f798ea52ee30c99dcb9c7e079c79659c2ffd9927976ab0093eb3003db7a80ff517fb25e7d1f4d95c602ad&ascene=0&uin=Mjk1ODMyNTYyMg%3D%3D&devicetype=iMac+MacBookPro11%2C4+OSX+OSX+10.11.1+build(15B42)&version=11020201&pass_ticket=R6pckpGE0E2s4Glv9xfkwcXltT2IyLOoSgjYv8LFO%2Bbf7dCsH7csTqs%2BqUqWZJaF

 

事务的隔离性

 

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对事务隔离性的定义[1]:

 

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事务隔离级别下,那么如果根据下面的步骤运行:

 

Time

T1

T2

|

|

|

|

|

|

V

BEGIN;

 

DELETE FROM P WHERE a <= 6;

 
 

BEGIN

 

INSERT INTO P SELECT 3;

 

COMMIT;

COMMIT;

 

 

最终表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标准没有从隔离程度进行定义,而是定义了事务的隔离级别,同时定义了不同事务隔离级别解决的三大并发问题:

 

Isolation Level

Dirty Read

Unrepeatable Read

Phantom Read

Read UNCOMMITTED

YES

YES

YES

READ COMMITTED

NO

YES

YES

READ REPEATABLE

NO

NO

YES

SERIALIZABLE

NO

NO

NO

 

从上表可以发现隔离级别和隔离性之间有着不同的含义。那为什么各个数据库厂商更倾向于选择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大会上[3],有人提出了Serializable Snapshot Isolation(SSI),从而解决了之前SI事务隔离级别存在的问题。PostgreSQL9.1版本在此论文基础上实现了SSI事务隔离级别并做了相应的优化。此外,在2012年的VLDB大会上PostgreSQL发布了相应的论文[4],有兴趣的读者可以继续研究。

 

基于快照的事务隔离级别(不论SI还是SSI)性能较之经典的SERIALIZABLE事务隔离级别提升非常多,但其存在两个问题不容忽视。一是其会导致“错误”的回滚,因为其策略就是保证正确,虽然有时可能会误杀一些没有问题的事务。二是对于大事务的支持需要额外的内存保证,如果修改的数据量特别大,那么这可能会导致内存溢出的问题发生。但不论怎么说,SSI可能都是未来的一个默认事务隔离级别发展的方向。期待MySQL数据库也能尽快支持。

 

参考文献

 

  1. Jim Gray, http://amturing.acm.org/info/gray_3649936.cfm, 1998

  2. Jim Gray, Andreas Reuter, Transaction Processing — Concepts and Techniques, 1993, Morgan Kaufmann, ISBN 1-55860-190-2

  3. Michael J. Cahill, Uwe Röhm, and Alan D. Fekete. 2008. Serializable isolation for snapshot databases. In SIGMOD ’08: Proceedings of the 2008 ACM SIGMOD international conference on Management of data, pages 729–738, New York, NY, USA. ACM.

  4. Dan R. K. Ports and Kevin Grittner. 2012. Serializable Snapshot Isolation in PostgreSQL. Proceedings of the VLDB Endowment vol. 5 (12) , August 2012 (pp. 1850--1861)

  5. https://wiki.postgresql.org/wiki/Serializable#SSI_Algorithm

  6. 姜承尧, MySQL技术内幕:InnoDB存储引擎机, 械工业出版社, 2011

  7. 姜承尧, MySQL内核:InnoDB存储引擎 卷1, 电子工业出版社, 2014

[转载] 你真的明白事务的隔离性吗?

标签:

原文地址:http://www.cnblogs.com/zhengran/p/4948977.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!