在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提交。
分享到:
相关推荐
本文将深入探讨“Oracle事务回滚存储过程”这一主题,旨在理解其核心概念、工作原理以及实际应用。 ### Oracle事务 在数据库操作中,事务是一系列操作的集合,这些操作要么全部成功,要么全部失败。事务具有ACID...
在数据库管理系统中,事务处理是确保数据一致性和完整性的关键机制。Oracle和MySQL作为两大...通过本文的分析和代码示例,读者应该能够更深入地理解Oracle与MySQL在事务处理上的差异,并在实际应用中做出更合适的选择。
6. **并发控制与事务管理**:Oracle使用多版本并发控制(MVCC)来实现事务的隔离级别,书中有望深入讨论行级锁定、死锁检测及解决策略。 7. **高可用性与灾难恢复**:介绍RAC(Real Application Clusters)、数据...
通过深入理解Oracle事务的这些基本概念和特性,数据库管理员和开发人员能够更好地控制数据的变更,确保数据的完整性和一致性,从而提高系统的稳定性和可靠性。实践中,应根据具体的应用场景和需求选择合适的事务隔离...
在这个主题中,我们将深入探讨Oracle事务的几个关键概念。 1. 事务的特性(ACID) - 原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成,不会留下部分完成的操作。 - 一致性(Consistency):...
4. **事务处理**:Oracle支持ACID(原子性、一致性、隔离性和持久性)属性,保证了事务处理的可靠性和一致性。 5. **并发控制**:Oracle使用多版本并发控制(MVCC),允许多个用户同时访问同一数据,减少了锁的使用...
### JDBC专题(六)-JDBC专题-事务的隔离级别 #### 一、事务的基本概念与特性 事务在数据库管理中扮演着极其重要的角色,尤其是在处理关键业务逻辑时,确保数据的一致性和完整性至关重要。根据提供的文件信息,我们...
5. **事务管理**:掌握ACID(原子性、一致性、隔离性和持久性)特性,了解提交、回滚和保存点操作。 6. **并发控制**:Oracle使用行级锁定和多版本并发控制(MVCC)来处理并发问题,防止死锁和数据不一致。 7. **...
隔离级别(如READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE)控制并发事务间的可见性。 10. **存储过程和函数**:存储过程和函数是预编译的SQL和PL/SQL代码块,可以封装复杂的业务逻辑并重复...
最后,本书以并发控制和多版本读一致性为核心,深入讨论了事务隔离级别对数据库性能和数据完整性的影响。通过理解不同的隔离级别(如READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE和READ ONLY)...
通过深入学习"MLDN魔乐科技_Oracle课堂13_事务处理",不仅可以理解Oracle事务的基础概念,还能掌握如何在实际开发中有效地管理事务,从而确保数据的安全性和系统的稳定性。该课程可能涵盖事务的启动、提交、回滚,...
参与者可能需要使用这个文件执行SQL语句,以亲身体验事务的各种操作,如模拟并发问题,学习如何设置事务隔离级别,以及理解回滚段在回滚事务中的作用。 在这个视频笔记中,我们可能会学习到以下知识点: 1. **事务...
在Oracle数据库中,事务是数据库操作的基本单位,通常具有ACID(原子性、一致性、隔离性和持久性)特性。原子性确保事务要么全部完成,要么全部不完成;一致性保证事务前后数据库处于逻辑一致的状态,符合预设的业务...
在Oracle中,可以通过设置事务隔离级别和使用死锁检测机制来避免这种情况。 5. **工具支持**: 标签提到的“工具”可能指的是数据库管理和开发工具,如SQL Developer或PL/SQL Developer,这些工具可以帮助开发者更...
通过深入理解和实践Oracle数据库的事务管理,可以有效地提高系统的稳定性和数据的可靠性。本教程的26页内容将逐步引导学习者掌握Oracle数据库管理和事务处理的各个方面,对于提升数据库管理技能具有极大的帮助。
##### Oracle事务的实现 Oracle 在逻辑上通过Undo表空间(Undo Tablespace)来实现事务处理。Undo表空间包含了Undo段(Undo Segments),而Undo段又包含了Undo数据(Undo Data)。Undo数据是支持事务的基本逻辑单元。 - *...
Oracle支持四种事务隔离级别,它们决定了事务如何与其他并发事务交互: 1. **读未提交(READ UNCOMMITTED)**:最低级别,允许读取未提交的数据,可能导致脏读。 2. **读已提交(READ COMMITTED)**:默认级别,每...