深入理解oracle的事务隔离性

在Oracle关系数据库中,我们先来看下面这个问题:

A事务:select <cols> from T where id  > 10 and id < 10000;

B事务:update T set id = 45000 where id = 4501

两个事务按下面的顺序执行:

A事务:|--------------------------------|commit

B事务:        |-------------|commit

也就是A事务先开始执行,过一段时间B事务再开始执行,但是B事务先执行完并commit提交了,A事务又过了一段时间才完成。那么问题来了,在这种情况下,问A事务能不能取得正确的结果,两个事务之间会不会有干扰,怎么干扰?

这是一个典型的关系型数据库事务的隔离性问题,而且,针对不同的数据库(存储引擎),可能会有不同的表现。

根据上面的描述,以oracle为例,它的缺省数据库隔离级别是读已提交(read-committed),事务A持有一个读锁(瞬间共享读锁),B持有一个排它写锁。

Read Committed读已提交的官方定义是,通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。

按照读已提交的定义,似乎按上题的条件,A,B两个事务都能够正确完成并commit提交。

但关系数据库厂商,它们的产品往往不会完完全全的按照规范来实现,总会附加一些自己特有的东西在里面。那么我们接下来详细分析一下,oracle是怎样处理的,SQL语句执行的内部过程相当复杂,大概比较显式和通俗易懂的是,先运行执行计划,然后执行SQL优化等策略,接着可能根据关键字,进行加锁处理,上下文切换等操作,比如select语句就会加一个读锁。

在执行DML语句时,Oracle会给每一行增加一个sn序列号,比如select <cols> from T where id  > 10 and id < 10000;这条语句,查询出将近1w条数据,在执行扫描的时候,发现符合条件的行就会加一个sn(实际操作时,可能是和内存中某个sn数值关联起来),这个sn序列号实际上被当做乐观锁使用。

那么可能出现下面的情况,事务A的select语句还没有执行完,当执行到2000条的时候,B开始了一个update T set id = 45000 where id = 4501的事务,由于在oracle中,写锁的级别高于读锁,因此这时候B事务的update语句取得写锁,成功执行完并commit,交出写锁。

当先开始的select语句执行到4501时,如果此时B事务已经commit,那么A事务会接着执行下去,成功commit,反之,当A事务执行到4501行时,B事务还未commit,那么二者的锁在4501这条数据发生冲突,这时整个A事务就会出错。

这里插一句,对于DML的select语句来说,只具有读一致性,所以失败了仅仅是报错放弃,不会回滚。

然而,上面的描述却有一个知识缺失点,就是所谓的MVCC(Multi-Version Concurrency Control)---基于多版本的并发控制协议 (注:与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control)。MVCC最大的好处是:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能,现阶段几乎所有的RDBMS,都支持了MVCC。

在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁(一种就是上面提及的sn序列号方式的乐观锁),保证其他事务不会再并发修改这条记录。

在oracle里,undo就是所谓的快照。如果undo够大的话,A事务的select返回的是没有执行update的语句前的数据;如果undo不够大,A事务的select会直接报错没有返回值,因为是隐式提交,所以并不会rollback回滚。

这就是oracle的经典错误ORA-01555快照过旧。

再回到一开始的原题目中,当执行事务A的select语句时,并没有明确指出是快照读还是当前读。因此,为严密起见,我们最终的结果是:

1.如果A事务执行的是快照读,如果undo够大的话,A,B事务都能够正确commit提交,A事务的select返回的是没有执行update的语句前的数据;如果undo不够大,B事务能够正确commit,A事务的select会直接报错没有返回值,事实上数据库的读写事务,绝大多数都属于这种情况;

2.如果A事务执行的是当前读,那么当A事务的select读操作和B事务的update写操作没有冲突时(不会同时读写4501那一行),两个事务都能正确执行;反之,A事务是有可能出错的。并不是A事务只要先执行,两个事务就一定能成功commit提交。

时间: 2024-11-09 02:26:01

深入理解oracle的事务隔离性的相关文章

数据库:自己理解的“数据库事务隔离级别”

转载请注明出处: jiq?钦's technical Blog - 季义钦 引言:在网上搜了很多关于事务的文章,感觉单独来看都很难看懂,所以综合自己的理解写一篇我自己能理解的关于关系型数据库事务的文章. 一.事务特征 我们都知道数据库事务具备ACID特性: Atomic(原子性):一个事务要么成功,要么失败 Consistency(一致性):一致性代表了底层数据存储的完整性.事务执行前后数据库都必须处于一个合法的状态.什么才是一个合法的状态? 比如满足数据库的唯一性约束.数据类型验证.引用完整性

谈数据库事务隔离性

写在前面 近两年分布式数据库技术加速发展,而由于金融行业技术生态的限制,周围很多同学对其并没有深入的了解,所以进行高性能.高可靠系统设计时往往缺少这一利器.Ivan希望以系列文章的方式与大家交流探讨,加深我们对分布式数据库的认识.本文是该系列文章的第一篇,主要探讨事务管理中的隔离性,厘清相关概念和关键技术,为后面阐述分布式数据库的事务管理做一个铺垫,姑且算是一篇前传吧. 正文 我们首先从定义出发,事务管理包括原子性.一致性.隔离性和持久性四个方面,即ACID.所有数据库专著都会给出这个四个特性的

oracle的事务隔离级别和读一致性

oracle提供了三个隔离级别: 1.读提交 ,简而言之只能读取语句开始执行前提交的数据 2.串行,这个好理解,就是事务串行运行,避免经典的三个场景-脏读.不可重复读.幻读. 3.只读,oracle已经实现的只读模式. -- 这些都很容易理解,问题的关键是解决一些实际的问题,例如典型的汽车票销售. 1.对于查票事务而言,使用简单的读提交隔离级别即可,读取那些可售票(状态不是已经售出或者正在销售的) 2.对于售票事务而言,只需要简单使用窜行隔离级别即可,在开始购买时候,先设置标记为正在销售,完成之

&lt;事务隔离性&gt;

Overview 事务的隔离性是指在并发环境中,并发的事务是隔离的.一个事务的执行不能被其他事务干扰. 也即,不同的事务并发操作相同数据时,每个事务都有各自完整的数据空间. 隔离性 在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同,包括: 未授权读取,也称为读未提交(Read Uncommitted).该级别允许脏读取,其隔离级别最低.[关于脏读,幻读,blabla...请往下拉].如果一个事务正在处理某一数据,并对其进行了更新,但同时尚未完成事务,因此还未进行事务提交

5分钟带你读懂事务隔离性与隔离级别

前言 我们在上一章节中介绍过数据库的带你了解数据库中事务的ACID特性的相关用法.本章节主要来介绍下数据库中一个非常重要的知识点事务的隔离级别.如有错误还请大家及时指出~ 问题: 事务的隔离级别有哪些? 如果并发事务没有进行隔离,会出现什么问题? 以下都是采用mysql数据库 在多个事务并发做数据库操作的时候,如果没有有效的避免机制,就会出现种种问题.大体上有以下问题: 一.引发的问题 在并发事务没有进行隔离的情况下,会发生如下问题. 问题一:脏读 脏读指一个事务读取了另外一个事务未提交的数据.

Mysql事务隔离性与相关锁的总结

事务隔离级别 隔离级别 脏读 不可重复读 幻读 读未提交 可以出现 可以出现 可以出现 读提交 不允许出现 可以出现 可以出现 可重复读 不允许出现 不允许出现 可以出现 序列化 不允许出现 不允许出现 不允许出现 注意点 上述隔离级别都是这么定义的,但是InnoDB和Falcon存储引擎已经通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了幻读问题. 已提交读 ReadCommitted 读取 不加锁 写入 加行锁(如果按索引过滤,那么只

理解Sql Server 事务隔离层级(Transaction Isolation Level)

关于Sql Server 事务隔离级别,百度百科是这样描述的 隔离级别:一个事务必须与由其他事务进行的资源或数据更改相隔离的程度.隔离级别从允许的并发副作用(例如,脏读或虚拟读取)的角度进行描述. 隔离级别共5种: read uncommitted | 0 未提交读read committed | 1 已提交读repeatable read | 2 可重复读serializable | 3 可序列化snapshot 快照(2005版本以后新加) 以下面的图为例,在事务A中会根据条件读取TABLE

sql server 事务隔离性 snapshot 、read committed说明

一. --该 read committed 默认事务隔离级别 在 systemuser修改事务未完成时 select * from [SystemUser] where id=62; 该语句是不可读取的 set transaction isolation level read committed; begin transaction update [SystemUser] set LoginId='test' where id=62; waitfor delay '00:00:10' commi

[MySQL]对于事务并发处理带来的问题,脏读、不可重复读、幻读的理解与数据库事务隔离级别 - 分析脏读 &amp; 不可重复读 &amp; 幻读

刚开始写博客.. 写的太low. 1.数据库的两种读,每种读读的数据版本不一样,所以也称为MVCC,即多版本并发控制 a) 快照读 select * from where xxx  这种形式的都是快照读. b) 当前读 update , insert ,delete ,select xx from xx for update ,  in share mode 都是当前读 当前读会等待,不会返回数据的历史版本 2.mvcc 的实现原理 mvcc是基于read view.活跃事务列表 做的,以后的文