René Nyffenegger's collection of things on the web
René Nyffenegger on Oracle - Most wanted - Feedback -
 

Locks in Oracle

create table lck (a number, b number);

insert into lck values (1,2);
insert into lck values (2,4);
insert into lck values (3,6);
insert into lck values (4,8);
insert into lck values (5,3);
insert into lck values (6,5);
insert into lck values (7,7);

commit;
We use two sessions (distinguishable by two colors and being on the left or right side) to investigate Statement-level read consistency, and a third to select from v$lock
First, we find the session id of the two participating sessions:
SQL> select sid from v$session where audsid=userenv('SESSIONID');

       SID
----------
        14
SQL>select sid from v$session where audsid=userenv('SESSIONID');

       SID
----------
        10
Now, we're inserting a row in the first session (sid=14).
SQL> insert into lck values (1000,1001);

1 row created.

SQL> select * from lck;

         A          B
---------- ----------
         1          2
         2          4
         3          6
         4          8
         5          3
         6          5
         7          7
      1000       1001

8 rows selected.
 
How does that influence v$lock?
SQL> select sid,type,id1,lmode,request from v$lock where sid in (10,14);

       SID TY        ID1      LMODE    REQUEST
---------- -- ---------- ---------- ----------
        14 TX     262153          6          0
        14 TM       4145          3          0
Session 14 (the one that inserted a row) has obviously aquired two locks (request = 0). One of these locks is a Transaction Lock (type=TX), the other is a DML or Table Lock (type=TM). Mode 3 means: Row Exclusive which acutally makes sense. Now, we can use obj$ to verify if the TM Lock is indeed put on the table LCK:
SQL> select name from sys.obj$ where obj# = 4145 ;

NAME
------------------------------
LCK
What does the 2nd session see if it queries LCK?
 
SQL>select * from lck;

         A          B
---------- ----------
         1          2
         2          4
         3          6
         4          8
         5          3
         6          5
         7          7

7 rows selected.
The 1st session has not yet commited (or rollbacked) its session, so the changes are not visible to other sessions.
Now, let's have the first session insert another row.
SQL> insert into lck values (1001,1000);

1 row created.
 
We'd expect v$lock to have an row more (for this 2nd inserted row). But never believe your feelings...
SQL> select sid,type,id1,lmode,request from v$lock where sid in (10,14);

       SID TY        ID1      LMODE    REQUEST
---------- -- ---------- ---------- ----------
        14 TX     262153          6          0
        14 TM       4145          3          0
Didn't much change, did it? Now, the 2nd session updates a row:
 
SQL>update lck set a=2000,b=2001 where a=1;

1 row updated.

SQL>select * from lck;

         A          B
---------- ----------
      2000       2001
         2          4
         3          6
         4          8
         5          3
         6          5
         7          7

7 rows selected.
And v$lock?
SQL> select sid,type,id1,lmode,request from v$lock where sid in (10,14);

       SID TY        ID1      LMODE    REQUEST
---------- -- ---------- ---------- ----------
        10 TX     327698          6          0
        10 TM       4145          3          0
        14 TX     262153          6          0
        14 TM       4145          3          0
 
SQL>insert into lck values (2001,2000);

1 row created.

SQL>select * from lck;

         A          B
---------- ----------
      2000       2001
         2          4
         3          6
         4          8
         5          3
         6          5
         7          7
      2001       2000

8 rows selected.
What happens, if the first session wants to update a row that was already updated (but not yet commited) by another session? The first session tries to do exactly that (the row in which a=1)
SQL> select * from lck;

         A          B
---------- ----------
         1          2
         2          4
         3          6
         4          8
         5          3
         6          5
         7          7
      1000       1001
      1001       1000

9 rows selected.

SQL> update lck set a=1002,b=1003 where a=1;
 
The session hangs until the session that has put a lock on the row in question commits (or rollbacks). This waiting is recorded in v$session_wait:
SQL> select event, seconds_in_wait, sid from v$session_wait where sid in (10,14);

EVENT                                                            SECONDS_IN_WAIT        SID
---------------------------------------------------------------- --------------- ----------
enqueue                                                                     1593         14
SQL*Net message from client                                                 2862         10
v$session_wait tells even how long (in secondes) the session waited. Now, let the 2nd session commit:
0 rows updated.

SQL>
SQL>commit;

Commit complete.
Note, this can be confusing. When the 1st session selected * from lck, it defenitively saw a row where a=1 but after seemingly updating it, it wasn't actually updated.
What do these sessions now see, if they both do a select *?
SQL> select * from lck;

         A          B
---------- ----------
      2000       2001
         2          4
         3          6
         4          8
         5          3
         6          5
         7          7
      1000       1001
      1001       1000
      2001       2000
SQL>select * from lck;

         A          B
---------- ----------
      2000       2001
         2          4
         3          6
         4          8
         5          3
         6          5
         7          7
      2001       2000
While the 1st session sees, what the 2nd session commited, the 2nd session does not see the uncommited changes of the first session. If the 1st session had been Transaction-level read consistent, it would not see any changes until it commits.