SQL标准隔离级别
在聊Oracle事务之前,首先先简单介绍下SQL标准。
SQL标准是ANSI定义的一套标准化的语法。它根据并发执行的事务之间出现的问题定义了四个级别的事务隔离,分别是:
- 读未提交(Read uncommitted)
- 读已提交(Read committed)
- 可重复读(Repeatable read)
- 序列化(Serializable)
这四个隔离级别与之关联的问题有三种:
- 脏读
- 不可重复读
- 幻读
接下来简单介绍下这三个问题是怎么产生的?
脏读,就是一个事务读取已由另一个尚未提交的事务写入的数据。简单来说,就是会话A执行了一个语句,将表中的数据进行了修改,此时还没有提交,会话B查看该表时,看到的数据是已经被会话A修改的数据,这种现象被称为“脏读”。
不可重复读,就是一个事务重新读取它之前读取的数据,发现另一个已提交的事务修改或删除了数据。简单来说,就是会话A第一次执行了一个查询语句,看到表A的数据是“张三”,再次执行该查询时,发现表A的数据是“李四”,这种现象被称为“不可重复读”。
幻读,就是事务重新运行返回一组满足查询条件的行的查询语句,发现另一个已提交的事务插入了满足条件的新记录。简单来说,就是事务在第一次查询时,有30条记录,但是在第二次查询时,同样的条件有35条记录,这种现象被称为“幻读”。
根据隔离级别和带来的问题可以将其划分为如下表格:
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(Read uncommitted) | 可能出现 | 可能出现 | 可能出现 |
读已提交(Read committed) | 不可能出现 | 可能出现 | 可能出现 |
可重复读(Repeatable read) | 不可能出现 | 不可能出现 | 可能出现 |
序列化(Serializable) | 不可能出现 | 不可能出现 | 不可能出现 |
以上就是SQL标准定义的隔离级别以及它们可能引起的数据问题。
Oracle事务隔离级别
在Oracle数据库中,完全兼容ANSI的标准SQL语句,但它的隔离级别与SQL标准提出的又略有不同。Oracle数据库中提供了三种事务的隔离级别:
- 读提交(Read Committed)
- 序列化(Serializable)
- 只读隔离级别(Read-Only)
这三种隔离级别中,前两种跟SQL标准提出的基本一致,但第三种是Oracle自己提供的隔离级别。在Oracle数据库中,默认隔离级别是读提交(Read Committed)。
读提交
在读提交隔离级别中,事务中的每个查询只能看到查询开始之前已提交的数据,而不是事务开始时的。例如事务A更新了某个表的数据,此时事务B查询该表只能看到事务A更改之前的数据,这也就意味着读提交隔离级别中,是可能会发生“不可重复读”和“幻读”的。
Oracle会在事务尝试修改由未提交的并发事务更新的行时,未提交的事务就被为阻塞事务。在此期间,当前的事务会一直等待阻塞的事务结束并释放锁。在这个等待的阶段,当前事务就可能会出现以下情况:
- 阻塞事务回滚,则等待事务继续更改之前被阻塞事务锁定的行,就像是阻塞事务不存在一样。
- 阻塞事务提交并释放其锁的话,则等待的事务继续对其新更新的行进行更新。
序列化
在序列化隔离级别中,事务只能看到在事务开始时提交的更改(注意,不是查询)以及事务本身所做的更改。例如,事务A在对某行执行更新操作,事务B在事务A执行后也对该行进行了更新(此时事务A还没提交),事务A在提交后,事务B再提交会报错ORA-08177。因为事务A已对该行数据进行了修改,事务B没法修改该行数据,需要重新开启事务才能继续修改。
从上述概念上来看,序列化隔离级别更适合在下面的场景中:
- 大型数据库和仅更新几行的小事务
- 并发事务修改相同行的机率比较低
- 较长时间运行的事务主要是只读的情况
只读隔离级别
在Oracle数据库中还提供了一种特殊的隔离级别,叫做只读隔离级别。它与序列化隔离级别很类似,唯一不同的地方就是只读事务不允许在事务中修改数据(除SYS用户外)。从这里也就可以看出,只读隔离级别基本上不会出现ORA-08177错误。
评论区