1

之后

create table l (id int primary key, val int);
insert into l values (0, 0);

并初始化两个 oracle 会话

alter session set isolation_level=serializable;

以下连续导致ORA-08177: can't serialize access for this transaction.

  session 1                           session 2                          
 -----------------------------------+-----------------------------------
  lock table l in exclusive mode                                         
 -----------------------------------+-----------------------------------
                                      lock table l in exclusive mode     
 -----------------------------------+-----------------------------------
  update l set val = 1 where id = 0   [blocked]                          
 -----------------------------------+-----------------------------------
  commit                              [blocked]                          
 -----------------------------------+-----------------------------------
                                      update l set val = 2 where id = 0  
 -----------------------------------+-----------------------------------
                                      [ORA-08177]                        

这是为什么?对我来说,它看起来非常连续。

4

1 回答 1

3

在可序列化事务开始后,当可序列化事务试图更改另一个事务(可序列化或不可序列化)已经更改的数据(甚至是位于同一数据块中另一个事务已经更改的数据附近的数据)时,您将收到ORA-08177错误信息。当您将事务隔离级别设置为 时serializable,需要牢记两件重要的事情:

  1. 仅当在可序列化事务(而不是语句)开始时已经提交了另一个事务对记录所做的更改时,可串行化事务才能更改记录。
  2. 读取一致性扩展到事务级别,而不是事务隔离级别设置为read committed(默认事务隔离级别)时的语句级别。

基本上,当可序列化事务开始时,它会获取自己的数据快照、已提交数据,并仅对该快照进行操作,并且仅查看自己已提交的数据——在获取新的数据快照之前,无法看到其他事务数据已提交。在您结束(提交或回滚)一个可序列化事务并启动另一个事务后,将获取新的数据快照。

导致ORA-08177错误的简单示例:

-- /* test table */
SQL> create table t1(col) as 
       select 3 from dual;
Table created.

-- sqlplus session #1                     sqlplus #session 2
----------------------------------------------------------------------------
SQL> alter session 
       set isolation_level=serializable;

                                          SQL> alter session set
                                               isolation_level=serializable;

/*
   You start serializable transaction by locking the t1 table in 
   exclusive mode. 

 */

-- serializable transaction #1

SQL> lock table t1 in exclusive mode;    -- serializable transaction # 2
                                         -- snapshot of t1 has been acquired
SQL> update t1 set col = 5               SQL> lock table t1 in exclusive mode;
      where col = 3; 
                                         -- this update does not see changes 
1 row updated.                           -- transaction #1 has already made 
                                         -- to t1's row where col = 3. 
                                         SQL> update t1 set col = 7 
SQL> commit;                                   where col = 3;
                                         ERROR at line 1:
Commit complete.                         ORA-08177: can't serialize access 
                                                    for this transaction 

在上述情况下,Oracle 为了使您的数据库保持一致模式会向ORA-08177您抛出错误,因为它知道可序列化事务 #1 对col = 3未获得可序列化事务 #2的行进行了更改一个新的数据快照,但是 - 在旧快照上运行。

将显式排他表锁和可序列化事务一起使用似乎非常非常过分:a)对并发性的巨大打击;b) 为避免 ORA-08177您需要提交或回滚事务引发ORA-08177错误并重试,一旦您发出提交或回滚,排他表锁将立即释放。

于 2013-11-12T10:56:50.680 回答