事务隔离级别:一个事务对数据库的修改与并行的另一个事务的隔离程度。
两个并发事务同时访问数据库表相同的行时,可能存在以下三个问题:
1、幻想读:事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一行新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这条新纪录就是幻想。
2、不可重复读取:事务T1读取一行记录,紧接着事务T2修改了T1刚刚读取的记录,然后T1再次查询,发现与第一次读取的记录不同,这称为不可重复读。
3、脏读:事务T1更新了一行记录,还未提交所做的修改,这个T2读取了更新后的数据,然后T1执行回滚操作,取消刚才的修改,所以T2所读取的行就无效,也就是脏数据。
为了处理这些问题,SQL标准定义了以下几种事务隔离级别
READ UNCOMMITTED 幻想读、不可重复读和脏读都允许。
READ COMMITTED 允许幻想读、不可重复读,不允许脏读
REPEATABLE READ 允许幻想读,不允许不可重复读和脏读
SERIALIZABLE 幻想读、不可重复读和脏读都不允许
Oracle数据库支持READ COMMITTED 和 SERIALIZABLE这两种事务隔离级别。所以Oracle不支持脏读
SQL标准所定义的默认事务隔离级别是SERIALIZABLE,但是Oracle 默认使用的是READ COMMITTED
设置隔离级别使用 SET TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]
下面是oracle 设置SERIALIZABLE隔离级别一个示例:
左面是事务T1,右面是事务T2,因为T2级别为SERIALIZABLE,所以即使事务T1在提交了数据之后,事务T2还是看不到T1提交的数据,幻想读和不可重复读都不允许了。
那如何能查看到T1新增的记录呢? 上面T1和T2是并发执行,在T1执行insert的时候事务T2已经开始了,因为T2级别是SERIALIZABLE,所以T2所查询的数据集是T2事务开始前数据库的数据。即事务T1在事务T2开始之后的insert和update操作的影响都不会影响事务T2。现在重新开启一个事务T3 就可以看到T1新增的记录了。
当下列事件发生时,事务就开始了:
1、连接到数据库,并执行第一条DML语句
2、前一个事务结束后,又输入了另一条DML语句
隔离级别(isolation level),是指事务与事务之间的隔离程度。
显然,事务隔离程度越高,并发性越差、性能越低;事务隔离程度越低,并发性越强、性能越高。
ANSI/ISO SQL92标准中定义了4种事务隔离级别:
1. 序列化(serializable)
最高隔离级别。系统中所有的事务都是一个接一个执行的。因此也就不会发生任何事务之间的冲突问题。
2. 可重复读(repeatable read)
一个事务所读取的数据记录不允许被其他事务所修改。
3. 读已提交(read committed)
该级别允许其他事务修改当前事务所读取的数据记录,并且那个事务提交之后,当前事务可以看到修改后的数据。
4. 读未提交(read uncommitted)
该级别允许其他事务修改当前事务所读取的数据记录,并且那个事务尚未提交时,当前事务就可以看到修改后的数据。即允许脏读。
事务隔离级别不同,执行一条数据库查询,得到的结果很可能让你感到意外,下面是这些情况的总结:
1. 脏读
读取了其他事务还没有提交的数据。
2. 不可重复读
当前事务已经读取的数据记录,被其他事务修改或删除。
3. 幻影读
其他事务插入了新的数据,当前事务以相同的查询条件,在那个事务插入数据之前和之后查询数据,得到的数据记录的条数不一样。
隔离级别 |
脏读 |
不可重复读 |
幻影读 |
序列化 |
N |
N |
N |
可重复读 |
N |
N |
Y |
读已提交 |
N |
Y |
Y |
读未提交 |
Y |
Y |
Y |
Oracle明确支持ANSI/ISO SQL92中定义的serializable和read committed两种事务隔离级别。
同时,Oracle还提供了自己独有的事务隔离级别:read only。
所以,可以说Oracle共支持3种事务隔离级别:
1. serializable
2. read committed
3. read only
Oracle默认的隔离级别是read committed。