سؤال

After a

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

and initializing two oracle sessions

alter session set isolation_level=serializable;

the following succession leads to a 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]                        

Why is that? It looks perfectly serial to me.

هل كانت مفيدة؟

المحلول

When serializable transaction is trying to change data that another transaction(serializable or not) has already changed (or even data that reside near to the data another transaction has already changed in the same data block) after that serializable transaction began, you'll receive the ORA-08177 error message. When you are setting transaction isolation level to serializable, there are two important things needed to be kept in mind:

  1. Serialzable transaction can change a record only if changes to that record made by another transaction(s) were already committed by the time the serializable transaction (not the statement) began.
  2. Read consistency is extended to transaction level, not statement level as it is when transaction isolation level is set to read committed(default transaction isolation level).

Basically, when serializable transaction begins, it acquires its own snapshot of data, committed data, and operates on that snapshot only, and sees its own committed data only - cannot see committed by another transaction data until it acquires a new snapshot of data. And the new snapshot of data will be acquired after you end (commit or rollback) one serializable transaction and start another one.

Simple example which leads to ORA-08177 error:

-- /* 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 

In the above situation Oracle, in order to keep your database in a consistent mode throws the ORA-08177 at you, because it's aware of the fact that the serializable transaction #1 made changes to the row(s) where col = 3 and serializable transaction #2 has not acquired a new snapshot of data, yet - operates on old one.

It seems to be very, very excessive to use explicit exclusive table lock and serializable transaction together: a) tremendous hit upon concurrency; b) In order to avoid the ORA-08177 you need to commit or rollback transaction that raises ORA-08177 error and retry it again, and as soon as you issued commit or rollback, the exclusive table lock would be immediately released.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top