ANSI SQL-92的non-Repeatable read和phantom row两种isolation level的差别

本文详细解释了SQL数据库中事务的三种不完整情况:脏读、不可重复读和幻读。通过具体实例演示了不同事务隔离级别下这些现象的表现形式,并探讨了如何通过设置事务隔离级别来控制这些行为。

我可以通过set transaction isolation level来控制数据库的事务完整性,对事务完整性的破坏有三种情况
dirty read > non repeatable read > phantom row。dirty read谁都容易理解,书上写的也是很明白的,就是事务1可以读取到事务2还没有提交的被修改的数据。
主要就是后两个non repeatable read 和phantom row,以前看了书也没搞明白是怎么回事,今天又看了看书,并做了下实验总算弄明白了,以前书上讲的是没错,但是感觉没有把话说透了。
non repeatable read是这样的情况:
begin tran t2
select * from t where id = 1
这时候不进行commit tran,假如得到的结果是
id   name
1    hello
这时在另外的查询窗口里再开始一个事务
begin tran t1
update t set name = 'hahaha' where id = 1
commit tran
这时候,我们再回到事务t2的窗口,再执行 select * from t where id = 1,我们将能看到name变成了hahaha
这种情况在sqlserver的默认的read committed isolation level下是允许的。
而phantom row 的情况是:
begin tran t1
select * from t where name like 'ha%'
假如返回的结果是
id     name
2       ha1
3       ha2
这时候在另一个查询窗口中开始另一个事务
begin tran t1
update t set name = 'hahaha' where id = 1
commit tran
然后再回到事务t1的窗口,还执行select * from t where name like 'ha%',这时候就会多查出id=1的那行。

猛一看non repeatable read 和phantom row好像没有太大差别,都是能在事务2中看到事务1已经提交的结果。关键是phantom row的情况下是不允许non repeatable read的情况出现。具体的来说,在只允许phantom row的情况下,对应sqlserver的set transaction isolation repeatable read,先开始一个查询的事务t1 它查询出了id 为1,2,3的三行,这时候t1没有提交,另外开始一个更新事务t2对id为2的行进行更新,这时候更新将无法进行,因为这种行为就属于non repeatable read的行为,但是如果对id为1,2,3之外的行进行更新,就不会有问题,如果对其他的行的更新后,使其他行的条件也符合事务t1中的刚才进行的查询的条件,则在事务T1没有被提交前再进行刚才的查询被修改后的行也会出现在查询结果中,这就出现了phantom row。

其实可以这样来理解,non repeatable read就是当一个事务在进行查询的时候,它不会对它查询到的行加锁,所以其他的事务可以来对其进行修改,但是在只允许phantom row的情况下,则是当一个事务在查询的时候,会对它查询到的行加锁,以防止其他的事务进行修改,但是不会对没有查询到的行进行加锁,其他的事务仍然可以对那些没被查到的行进行修改,当修改被提交之后,某些行符合了查询事务的查询的条件,则那些被修改的行也会被查询事务查询到,并被加上锁以防止被其他事务修改。如果是最严格的事务完整性的话,如果查询事务在更新事务之前开始,则更新事务所做的一切提交的修改都不应该被查询事务查询到,虽然我没做试验,但我估计当连PHANTOM ROW都不允许的情况下(这我只是估计而已,实际未必会是这样,没做实际验证,懒得做了),在sqlsever里恐怕当开始了查询事务之后,再开始的更新事务将根本无法运行下去,只能一直等到查询事务提交之后才能继续执行。

<think>好的,我现在需要回答用户关于Oracle数据库支持的事务隔离级别的问题。用户还提到了Read Committed、Repeatable Read、SerializableRead-Only的具体含义。首先,我需要回顾之前提供的引用内容,特别是引用[4],其中提到Oracle不支持READ UNCOMMITTEDREPEATABLE READ。但用户的问题中提到了Repeatable Read,这可能需要进一步确认。 根据引用[4],ISO标准定义了四个隔离级别:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE。但Oracle数据库只支持READ COMMITTEDSERIALIZABLE,以及READ ONLY模式。用户可能混淆了标准隔离级别Oracle实际支持的级别。需要明确说明Oracle不支持REPEATABLE READ,但通过某些机制如快照来实现类似效果。 接下来,我需要整理Oracle支持的具体隔离级别: 1. **Read Committed**:默认级别,保证事务只能读取已提交的数据,避免脏读。但可能出现不可重复读幻读。 2. **Serializable**:最高隔离级别,保证事务执行结果与串行执行一致,避免脏读、不可重复读幻读。 3. **Read-Only**:事务只能查询数据,不能修改,提供一致性视图。 需要注意的是,Oracle的SERIALIZABLE级别使用快照机制,而非严格的锁机制,这可能与其它数据库实现不同。此外,Oracle不支持REPEATABLE READ隔离级别,但通过Read Committed的多版本控制,可以在某些情况下避免不可重复读。 还需要检查引用中的其他信息,比如引用[3]提到的事务隔离级别对比表格,确认Oracle在不同隔离级别下的表现是否符合标准。例如,在Read Committed下,Oracle不会出现脏读,但可能出现不可重复读幻读;在Serializable下,三者都不会出现。 另外,引用[4]指出InnoDB的默认隔离级别是REPEATABLE READ,但Oracle的默认是Read Committed,这点需要明确区分,避免用户混淆。 最后,总结Oracle支持的隔离级别及其含义,确保回答准确,并引用相关来源支持结论。</think>### 核心答案 Oracle数据库支持以下三种事务隔离级别: 1. **`READ COMMITTED`(默认级别)** 2. **`SERIALIZABLE`** 3. **`READ ONLY`** **注意**:Oracle **不**支持`READ UNCOMMITTED``REPEATABLE READ`隔离级别[^4][^3]。 --- ### 详细解析 #### 1. **`READ COMMITTED`(读已提交)** - **定义**:事务只能读取其他事务已提交的数据,避免脏读(Dirty Read)[^3][^4]。 - **特点**: - 通过**多版本并发控制(MVCC)**实现,查询时基于事务开始时的数据快照。 - **可能发生**:不可重复读(Non-repeatable Read)、幻读(Phantom Read)[^3]。 - **示例**: ```sql -- 会话A UPDATE employees SET salary = 15000 WHERE id = 101; -- 未提交时,会话B查询仍看到原值(无脏读) COMMIT; -- 提交后,会话B查询到新值 ``` #### 2. **`SERIALIZABLE`(可串行化)** - **定义**:事务执行结果与串行执行完全一致,避免脏读、不可重复读幻读[^3][^4]。 - **实现机制**: - 使用**快照隔离**(Snapshot Isolation),事务基于数据库的一致性视图操作,而非物理锁。 - 若检测到数据冲突(如其他事务修改了本事务的数据),会抛出`ORA-08177: 无法串行访问`错误[^4]。 - **适用场景**:高一致性要求的复杂事务(如金融对账)。 - **示例**: ```sql SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; SELECT * FROM orders WHERE status = 'PENDING'; -- 其他会话修改`status`字段时,当前事务会检测到冲突 ``` #### 3. **`READ ONLY`(只读)** - **定义**:事务仅允许查询,禁止任何数据修改操作(DML),提供一致性视图[^4]。 - **特点**: - 基于事务开始时的一致性快照,不受其他事务提交的影响。 - 适用于生成静态报表或数据分析。 - **示例**: ```sql SET TRANSACTION READ ONLY; SELECT SUM(sales) FROM financial_data; -- 允许 UPDATE financial_data SET sales = 0; -- 报错:ORA-01456: 只读事务中不允许DML操作 ``` --- ### 隔离级别对比 | 隔离级别 | 脏读 | 不可重复读 | 幻读 | 实现机制 | |----------------|------|------------|------|--------------------| | `READ COMMITTED` | × | √ | √ | MVCC(多版本控制) | | `SERIALIZABLE` | × | × | × | 快照隔离 | | `READ ONLY` | × | × | × | 一致性快照 | --- ### 常见问题 1. **Oracle为何不支持`REPEATABLE READ`?** - Oracle通过`READ COMMITTED`的MVCC机制`SERIALIZABLE`的快照隔离,已覆盖`REPEATABLE READ`的功能需求[^4]。 - 例如,在`READ COMMITTED`下,可通过`SELECT ... FOR UPDATE`显式加锁避免不可重复读。 2. **`SERIALIZABLE`隔离级别是否完全等同于串行执行?** - 否。Oracle的`SERIALIZABLE`通过乐观锁(快照)实现,仅在提交时检测冲突,而非物理阻塞其他事务[^4]。 3. **如何设置隔离级别?** ```sql -- 会话级设置 SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; SET TRANSACTION READ ONLY; -- 事务级设置 START TRANSACTION ISOLATION LEVEL SERIALIZABLE; ``` --- ### 运维建议 - **默认使用`READ COMMITTED`**:平衡一致性与性能,适合多数场景。 - **慎用`SERIALIZABLE`**:高冲突场景可能频繁触发`ORA-08177`,需结合重试机制。 --- ### 引用支持 > "Oracle数据库支持READ COMMITTED、SERIALIZABLEREAD ONLY隔离级别,不遵循ANSI SQL标准的全部定义"[^4]。 > "SERIALIZABLE级别通过快照隔离实现,而非传统锁机制"[^4]。 #### 相关问题 1. **Oracle的MVCC机制如何避免脏读?** - 查询基于数据块的版本历史,仅读取已提交的版本[^4]。 2. **如何监控Oracle事务的隔离级别?** - 通过`v$transaction`视图查看当前事务状态。 3. **`READ ONLY`事务能否查询到其他事务的提交?** - 否,其数据视图在事务开始时固定[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值