事务隔离级别学习

       事务(transaction)是数据库管理系统的执行单位,可以是一个数据库操作(如Select操作)或者是一组操作序列。事务ACID属性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。

       原子性:保证事务中的所有操作全部执行或全部不执行。例如执行转账事务,要么转账成功,要么失败。成功,则金额从转出帐户转入到目的帐户,并且两个帐户金额将发生相应的变化;失败,则两个账户的金额都不变。不会出现转出帐户扣了钱,而目的帐户没有收到钱的情况。

       一致性:保证数据库始终保持数据的一致性——事务操作之前是一致的,事务操作之后也是一致的,不管事务成功与否。如上面的例子,转账之前和之后数据库都保持数据上的一致性。

       隔离性:多个事务并发执行的话,结果应该与多个事务串行执行效果是一样的。显然最简单的隔离就是将所有事务都串行执行:先来先执行,一个事务执行完了才允许执行下一个。但这样数据库的效率低下,如:两个不同的事务只是读取同一批数据,这样完全可以并发进行。为了控制并发执行的效果就有了不同的隔离级别。针对多个事务并发情况

       持久性:持久性表示事物操作完成之后,对数据库的影响是持久的,即使数据库因故障而受到破坏,数据库也应该能够恢复。通常的实现方式是采用日志。

 

       事务隔离级别(transaction isolation levels):隔离级别就是对对事务并发控制的等级。ANSIISO SQL将其分为串行化(SERIALIZABLE)、可重复读(REPEATABLE READ)、读已提交(READ COMMITED)、读未提交(READ UNCOMMITED)四个等级。

       为了实现隔离级别通常数据库采用锁(Lock)。一般在编程的时候只需要设置隔离等级,至于具体采用什么锁则由数据库来设置。首先介绍四种等级,然后举例解释后面三个等级(可重复读、读已提交、读未提交)中会出现的并发问题。

       串行化(SERIALIZABLE):所有事务都一个接一个地串行执行,这样可以避免幻读(phantom reads)。对于基于锁来实现并发控制的数据库来说,串行化要求在执行范围查询(如选取年龄在10到30之间的用户)的时候,需要获取范围锁(range lock)。如果不是基于锁实现并发控制的数据库,则检查到有违反串行操作的事务时,需要滚回该事务。

       可重复读(REPEATABLE READ):所有被Select获取的数据都不能被修改,这样就可以避免一个事务前后读取数据不一致的情况。但是却没有办法控制幻读,因为这个时候其他事务不能更改所选的数据,但是可以增加数据,即前一个事务有读锁但是没有范围锁,为什么叫做可重复读等级呢?那是因为该等级解决了下面的不可重复读问题。

       读已提交(READ COMMITED):被读取的数据可以被其他事务修改。这样就可能导致不可重复读。也就是说,事务读取数据时获取读锁,但是读完之后立即释放(不需要等到事务结束),而写锁则是事务提交之后才释放。释放读锁之后,就可能被其他事物修改数据。该等级是Oracle默认的隔离等级。

       读未提交(READ UNCOMMITED):这是最低的隔离等级,允许其他事务看到没有提交的数据。这种等级会导致脏读(Dirty Read)。

       通过一些现象,可以反映出隔离级别的效果。这些现象有:

       更新丢失(lost update):当系统允许两个事务同时更新同一数据是,发生更新丢失。

       脏读(dirty read):当一个事务读取另一个事务尚未提交的修改时,产生脏读。

       非重复读(nonrepeatable read):同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。

       幻像(phantom read):同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻像读。

       下面是隔离级别及其对应的可能出现或不可能出现的现象

 

 

Dirty Read 

NonRepeatable Read 

Phantom Read 

Read uncommitted

Possible

Possible

Possible

Read committed

Not possible

Possible

Possible

Repeatable read

Not possible

Not possible

Possible

Serializable

Not possible

Not possible

Not possible

 

ORACLE的隔离级别

ORACLE提供了SQL92标准中的read committed和serializable,同时提供了非SQL92标准的read-only。

read committed:这是ORACLE缺省的事务隔离级别。

        事务中的每一条语句都遵从语句级的读一致性。

        保证不会脏读;但可能出现非重复读和幻像。

serializable:简单地说,serializable就是使事务看起来象是一个接着一个地顺序地执行。

        仅仅能看见在本事务开始前由其它事务提交的更改和在本事务中所做的更改。

        保证不会出现非重复读和幻像。

    Serializable隔离级别提供了read-only事务所提供的读一致性(事务级的读一致性),同时又允许DML操作。

       如果有在serializable事务开始时未提交的事务在serializable事务结束之前修改了serializable事务将要修改的行并进行了提交,则serializable事务不会读到这些变更,因此发生无法序列化访问的错误。(换一种解释方法:只要在serializable事务开始到结束之间有其他事务对serializable事务要修改的东西进行了修改并提交了修改,则发生无法序列化访问的错误。)

       If a serializable transaction contains data manipulation language (DML) that attempts to update any resource that may have been updated in a transaction uncommitted at the start of the serializable transaction, (并且修改在后来被提交而没有回滚),then the DML statement fails. 返回的错误是ORA-08177: Cannot serialize access for this transaction。

        ORACLE在数据块中记录最近对数据行执行修改操作的N个事务的信息,目的是确定是否有在本事务开始时未提交的事务修改了本事务将要修改的行。具体见英文:Oracle permits a serializable transaction to modify a data row only if it can determine that prior changes to the row were made by transactions that had committed when the serializable transaction began. To make this determination efficiently, Oracle uses control information stored in the data block that indicates which rows in the block contain committed and uncommitted changes. In a sense, the block contains a recent history of transactions that affected each row in the block. The amount of history that is retained is controlled by the INITRANS parameter of CREATE TABLE and ALTER TABLE. Under some circumstances, Oracle may have insufficient history information to determine whether a row has been updated by a "too recent" transaction. This can occur when many transactions concurrently modify the same data block, or do so in a very short period. You can avoid this situation by setting higher values of INITRANS for tables that will experience many transactions updating the same blocks. Doing so will enable Oracle to allocate sufficient storage in each block to record the history of recent transactions that accessed the block.

l          The INITRANS Parameter:Oracle stores control information in each data block to manage access by concurrent transactions. Therefore, if you set the transaction isolation level to serializable, you must use the ALTER TABLE command to set INITRANS to at least 3. This parameter will cause Oracle to allocate sufficient storage in each block to record the history of recent transactions that accessed the block. Higher values should be used for tables that will undergo many transactions updating the same blocks.

       read-only:

       遵从事务级的读一致性,仅仅能看见在本事务开始前由其它事务提交的更改。

       不允许在本事务中进行DML操作。

       read only是serializable的子集。它们都避免了非重复读和幻像。区别是在read only中是只读;而在serializable中可以进行DML操作。

l         Export with CONSISTENT = Y sets the transaction to read-only.

l          read committed和serializable的区别和联系:

l         事务1先于事务2开始,并保持未提交状态。事务2想要修改正被事务1修改的行。事务2等待。如果事务1回滚,则事务2(不论是read committed还是serializable方式)进行它想要做的修改。如果事务1提交,则当事务2是read committed方式时,进行它想要做的修改;当事务2是serializable方式时,失败并报错“Cannot serialize access”,因为事务2看不见事务1提交的修改,且事务2想在事务一修改的基础上再做修改。具体见英文:Both read committed and serializable transactions use row-level locking, and both will wait if they try to change a row updated by an uncommitted concurrent transaction. The second transaction that tries to update a given row waits for the other transaction to commit or roll back and release its lock. If that other transaction rolls back, the waiting transaction (regardless of its isolation mode) can proceed to change the previously locked row, as if the other transaction had not existed. However, if the other (blocking) transaction commits and releases its locks, a read committed transaction proceeds with its intended update. A serializable transaction, however, fails with the error "Cannot serialize access", because the other transaction has committed a change that was made since the serializable transaction began.

l         read committed和serializable可以在ORACLE并行服务器中使用。

l          关于SET TRANSACTION READ WRITE:read write和read committed 应该是一样的。在读方面,它们都避免了脏读,但都无法实现重复读。虽然没有文档说明read write在写方面与read committed一致,但显然它在写的时候会加排他锁以避免更新丢失。在加锁的过程中,如果遇到待锁定资源无法锁定,应该是等待而不是放弃。这与read committed一致。

l         语句级的读一致性

l          ORACLE保证语句级的读一致性,即一个语句所处理的数据集是在单一时间点上的数据集,这个时间点是这个语句开始的时间。

l          一个语句看不见在它开始执行后提交的修改。

l          对于DML语句,它看不见由自己所做的修改,即DML语句看见的是它本身开始执行以前存在的数据。

l         事务级的读一致性

l          事务级的读一致性保证了可重复读,并保证不会出现幻像。

l         设置隔离级别

l          设置一个事务的隔离级别

l         SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

l         SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

l         SET TRANSACTION READ ONLY;

l         设置增个会话的隔离级别

l         ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE;

l         ALTER SESSION SET ISOLATION_LEVEL READ COMMITTED;

 

猜你喜欢

转载自willwen.iteye.com/blog/1986439
今日推荐