Oracle中的锁,一共有6种模式:
0:none
1:null 空
2:Row-S 行共享(RS):共享表锁,sub share
3:Row-X 行独占(RX):用于行的修改,sub exclusive
4:Share 共享锁(S):阻止其他DML操作,share
5:S/Row-X 共享行独占(SRX):阻止其他事务操作,share/sub exclusive
6:exclusive 独占(X):独立访问使用,exclusive
Example Tables
The lock waits which can occur are demonstrated using the following tables.
Connect as SCOTT/TIGER or some dummy user to set up the test environment using the following SQL:
DROP TABLE tx_eg;
CREATE TABLE tx_eg ( num number, txt varchar2(10), sex varchar2(10) ) INITRANS 1 MAXTRANS 1;
INSERT into tx_eg VALUES ( 1, ‘First’,’FEMALE’ );
INSERT into tx_eg VALUES ( 2, ‘Second’,’MALE’ );
INSERT into tx_eg VALUES ( 3, ‘Third’,’MALE’ );
INSERT into tx_eg VALUES ( 4, ‘Fourth’,’MALE’ );
INSERT into tx_eg VALUES ( 5, ‘Fifth’,’MALE’ );
COMMIT;
In the examples below three sessions are required:
Ses#1 indicates the TX_EG table owners first session
Ses#2 indicates the TX_EG table owners second session
DBA indicates a SYSDBA user with access to View:V$LOCK
Waits due to Row being locked by an active Transaction
When a session updates a row in a table the row is locked by the sessions transaction. Other users may SELECT that row and will see the row as it was BEFORE the UPDATE occurred. If another session wishes to UPDATE the same row it has to wait for the first session to commit or rollback.
The second session waits for the first sessions TX lock in EXCLUSIVE mode.
–Ses#1:
update tx_eg set txt=’Garbage’ where num=1;
–Ses#2:
update tx_eg set txt=’Garbage’ where num=1;
–DBA:
select SID,TYPE,ID1,ID2,LMODE,REQUEST from v$lock where type=’TX’;
SID TY ID1 ID2 LMODE REQUEST
———- — ———- ———- ———- ———-
8 TX 131075 597 6 0
10 TX 131075 597 0 6
This shows SID 10 is waiting for the TX lock held by SID 8 and it wants the lock in exclusive mode (as REQUEST=6).
–DBA:
select sid,p1raw, p2, p3 from v$session_wait where wait_time=0 and event=’enqueue’;
SID P1RAW P2 P3
———- ——– ———- ———-
10 54580006 131075 597
> ~~~~ ~~ ~~~~~~ ~~~
> type|mode id1 id2
> TX 6 13107 597
The next select shows the object_id and the exact row that the session is waiting for. This information is only valid in V$SESSION when a session is waiting due to a row level lock.
As SID 10 is the waiter above then this is the session to look at in V$SESSION:
–DBA:
select ROW_WAIT_OBJ#,ROW_WAIT_FILE#,ROW_WAIT_BLOCK#,ROW_WAIT_ROW# from v$session
where sid=10;
ROW_WAIT_O ROW_WAIT_F ROW_WAIT_B ROW_WAIT_R
———- ———- ———- ———-
3058 4 2683 0
> The waiter is waiting for the TX lock in order to lock row 0
> in file 4, block 2683 of object 3058.
— Ses#1:
rollback;
–Ses#2:
rollback;
Waits due to Unique or Primary Key Constraint enforcement
If a table has a primary key constraint, a unique constraint or a unique index then the uniqueness of the column/s referenced by the constraint is enforced by a unique index. If two sessions try to insert the same key value the second session has to wait to see if an ORA-0001 should be raised or not.
–Ses#1:
ALTER TABLE tx_eg ADD CONSTRAINT tx_eg_pk PRIMARY KEY( num );
–Ses#1:
insert into tx_eg values (10,’New’,’MALE’);
–Ses#2:
insert into tx_eg values (10,’OtherNew’,null);
–DBA:
select SID,TYPE,ID1,ID2,LMODE,REQUEST from v$lock where type=’TX’;
SID TY ID1 ID2 LMODE REQUEST
———- — ———- ———- ———- ———-
8 TX 196625 39 6 0
10 TX 262155 65 6 0
10 TX 196625 39 0 4
This shows SID 10 is waiting for the TX lock held by SID 8
and it wants the lock in share mode (as REQUEST=4).
SID 10 holds a TX lock for its own transaction.
–Ses#1:
commit;
–Ses#2:
ORA-00001: unique constraint (SCOTT.TX_EG_PK) violated
–Ses#2:
rollback;
Waits due to Insufficient ‘ITL’ slots in a Block
Oracle keeps note of which rows are locked by which transaction in an area at the top of each data block known as the ‘interested transaction list’.
The number of ITL slots in any block in an object is controlled by the INITRANS and MAXTRANS attributes. INITRANS is the number of slots initially created in a block when it is first used, while MAXTRANS places an upper bound on the number of entries allowed. Each transaction which wants to modify a block requires a slot in this ‘ITL’ list in the block.
MAXTRANS places an upper bound on the number of concurrent transactions which can be active at any single point in time within a block.
INITRANS provides a minimum guaranteed ‘per-block’ concurrency.
If more than INITRANS but less than MAXTRANS transactions want to be active concurrently within the same block then the ITL list will be extended
BUT ONLY IF THERE IS SPACE AVAILABLE TO DO SO WITHIN THE BLOCK.
If there is no free ‘ITL’ then the requesting session will wait on one of the active transaction locks in mode 4.
–Ses#1:
update tx_eg set txt=’Garbage’ where num=1;
–Ses#2:
update tx_eg set txt=’Different’ where num=2;
–DBA:
select SID,TYPE,ID1,ID2,LMODE,REQUEST from v$lock
where type=’TX’;
SID TY ID1 ID2 LMODE REQUEST
———- — ———- ———- ———- ———-
8 TX 327688 48 6 0
10 TX 327688 48 0 4
This shows SID 10 is waiting for the TX lock held by SID 8
and it wants the lock in share mode (as REQUEST=4).
–Ses#1:
commit;
–Ses#2:
commit;
–Ses#1:
ALTER TABLE tx_eg MAXTRANS 2;
Ses#1:
update tx_eg set txt=’First’ where num=1;
–Ses#2:
update tx_eg set txt=’Second’ where num=2;
–Both rows update as there is space to grow the ITL list to accommodate
both transactions.
–Ses#1:
commit;
–Ses#2:
commit;
From 9.2 you can check the ITL Waits in v$segment_statistics with a query like:
SELECT t.OWNER, t.OBJECT_NAME, t.OBJECT_TYPE, t.STATISTIC_NAME, t.VALUE
FROM v$segment_statistics t
WHERE t.STATISTIC_NAME = ‘ITL waits’
AND t.VALUE > 0;
If need be, increase INITTRANS and MAXTRANS.
In earlier releases of Oracle Database, the MAXTRANS parameter limited the number of transaction entries that could concurrently use data in a data block. This parameter has been deprecated in 10g and higher. Oracle Database now automatically allows up to 255 concurrent update transactions for any data block, depending on the available space in the block.
Waits due to rows being covered by the same BITMAP index fragment
Bitmap indexes index key values and a range of ROWIDs. Each ‘entry’ in a bitmap index can cover many rows in the actual table. If 2 sessions wish to update rows covered by the same bitmap index fragment then the second session waits for the first transaction to either COMMIT or ROLLBACK by waiting for the TX lock in mode 4.
–Ses#1:
CREATE Bitmap Index tx_eg_bitmap on tx_eg ( sex );
–Ses#1:
update tx_eg set sex=’FEMALE’ where num=3;
–Ses#2:
update tx_eg set sex=’FEMALE’ where num=4;
–DBA:
select SID,TYPE,ID1,ID2,LMODE,REQUEST
from v$lock where type=’TX’;
SID TY ID1 ID2 LMODE REQUEST
———- — ———- ———- ———- ———-
8 TX 262151 62 6 0
10 TX 327680 60 6 0
10 TX 262151 62 0 4
–This shows SID 10 is waiting for the TX lock held by SID 8
–and it wants the lock in share mode (as REQUEST=4).
–Ses#1:
commit;
–Ses#2:
commit;
Other Scenarios
There are other wait scenarios which can result in a SHARE mode wait for a TX lock but these are rare compared to the examples given above.
Example:
If a session wants to read a row locked by a transaction in a PREPARED state then it will wait on the relevant TX lock in SHARE mode (REQUEST=4).
As a PREPARED transaction should COMMIT , ROLLBACK or go to an in-doubt state very soon after the prepare this is not generally noticeable..
ORA-1548 Dropping UNDO Tablespace Distributed Transaction Pending:Prepared / Dead [ID 1321093.1]
Modified 21-NOV-2011 Type PROBLEM Status PUBLISHED
In this Document
Symptoms
Cause
Solution
References
Applies to:
Oracle Server – Enterprise Edition – Version: 9.2.0.1 to 11.2.0.2 – Release: 9.2 to 11.2
Information in this document applies to any platform.
Symptoms
After creating a new Undo Tablespace, you are trying to drop the old Undo Tablespace and are getting the following error:
ORA-01548: active rollback segment ‘_SYSSMU51$’ found, terminate dropping
Cause
In most cases, this error is legitimate in that there is an active transaction still showing up as using the Undo Segment that is being referenced and we will need to clear that transaction before you will be able to drop the undo tablespace.
Solution
In this particular case there was a Distributed Transaction that was Prepared but Dead.
1). Check the status of the undo segments that are not either Online or Offline:
Select segment_name,status,tablespace_name from dba_rollback_segs where status not in (‘ONLINE’,’OFFLINE’) ;
You find you have segments that are ‘Partly Available’
This usually means they still have active transactions pending and you can not drop the tablespace until the transaction is committed or rolled back.
2). Use the following query to check for any Active Transactions on the Undo Segments reported above.
To check for any active transactions on a rollback segment:
SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */
KTUXESTA Status,
KTUXECFL Flags
FROM x$ktuxe
WHERE ktuxesta!=’INACTIVE’
AND ktuxeusn=
/
SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */ KTUXESTA Status, KTUXECFL Flags FROM x$ktuxe WHERE ktuxesta!=’INACTIVE’
AND ktuxeusn= 265;
KTUXEUSN KTUXESLT KTUXESQN STATUS FLAGS
———- ———- ———- —————- ————————
265 31 806703 PREPARED SCO|COL|REV|DEAD|EXTDTX
3). In the above case we can see that Undo Segment 265 has an Active Transaction that is showing as
PREPARED and DEAD
This is part of a distributed transaction. The DEAD indicates it is a failed distributed transaction but as it is PREPARED it may need to commit or roll back.
4). You can use the following queries to check for in doubt transactions:
SELECT LOCAL_TRAN_ID,GLOBAL_TRAN_ID,STATE,MIXED,COMMIT# FROM DBA_2PC_PENDING;
SELECT LOCAL_TRAN_ID,IN_OUT,DATABASE,INTERFACE FROM dba_2pc_neighbors;
In this case, we found no rows where returned from either query.
5). At this point you can use the following note to clean up the transactions:
“How To Resolve Stranded DBA_2PC_PENDING Entries (Doc ID 401302.1)”
For the transactions found in the Query executed in #2 above
Execute commands from section:
2.2 Distributed transaction without corresponding dba_2pc entries
6). Once these transactions have been cleared, you should now be able to drop the undo tablespace with out getting the ORA-1548.
How To Resolve Stranded DBA_2PC_PENDING Entries [ID 401302.1]
Modified 21-NOV-2011 Type BULLETIN Status PUBLISHED
Applies to:
Oracle Server – Enterprise Edition – Version: 8.1.5.0 to 11.1.0.6 – Release: 8.1.5 to 11.1
Information in this document applies to any platform.
Purpose
The purpose of this bulletin is to assist support analysts in understanding and
resolving the stranded dba_2pc_entries.
Scope and Application
The intended audience are support analysts having good experience on distributed
databases.
How To Resolve Stranded DBA_2PC_PENDING Entries
Contents
1. Problem Description
2. Solutions
2.1 Dba_2pc entries without a corresponding transaction
2.2 Distributed transaction without corresponding dba_2pc entries
2.3 How to PURGE the DISTRIBUTED transaction in PREPARED state, when COMMIT
or ROLLBACK FORCE hangs ?, where we have entries for both Distributed
transaction and dba_2pc entries.
1. Problem Description:
=======================
As a result of a failed commit of a distributed transaction, some entries can
be left in dba_2pc views, i.e. dba_2pc_pending and dba_2pc_neighbors. The RECO
process checks these views to recover the failed txn. However, in some cases
RECO cannot perform the recovery. One cause is that all sites involved in the
transaction not being accessible at the same time. Another cause is dba_2pc
views being inconsistent with the transaction table, which is the topic of
this article. This cause can further be classified as follows:
1. dba_2pc views have entries for a non-existent distributed transaction
2. There is a distributed transaction for which there are no entries in
dba_2pc views
3. How to PURGE the DISTRIBUTED transaction in PREPARED state, when COMMIT
or ROLLBACK FORCE hangs ?, where we have entries for both Distributed
transaction and dba_2pc entries.
Solutions to each subclass is provided in the rest of the article.
2. Solutions:
2.1 Dba_2pc entries without a corresponding transaction
In this case dba_2pc views show distributed transactions but there are no txns
in reality. If the state of the transaction is committed, rollback forced or
commit forced then this is normal and it can be cleaned up using
dbms_transaction.purge_lost_db_entry
However, if the state of the transaction is PREPARED and there is no entry in
the transaction table for it then this entry can be cleaned up manually as
follows:
set transaction use rollback segment SYSTEM;
delete from sys.pending_trans$ where local_tran_id = ;
delete from sys.pending_sessions$ where local_tran_id = ;
delete from sys.pending_sub_sessions$ where local_tran_id = ;
commit;
Example:
——–
The following query reports a dist. txn. in prepared state
select local_tran_id, state from dba_2pc_pending;
LOCAL_TRAN_ID STATE
———————- —————-
1.92.66874 prepared
Given that a transaction id is composed of triple,
‘1.92.66874’ is located in rollback segment# 1. To find out the list of
active transactions in that rollback segment, use:
SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */
KTUXESTA Status,
KTUXECFL Flags
FROM x$ktuxe
WHERE ktuxesta!=’INACTIVE’
AND ktuxeusn= 1; <== this is the rollback segment# no rows selected It is not possible to rollback force or commit force this transaction. rollback force '1.92.66874'; ORA-02058: no prepared transaction found with ID 1.92.66874 Hence, we have to manually cleanup that transaction: set transaction use rollback segment SYSTEM; delete from sys.pending_trans$ where local_tran_id = '1.92.66874'; delete from sys.pending_sessions$ where local_tran_id = '1.92.66874'; delete from sys.pending_sub_sessions$ where local_tran_id = '1.92.66874'; commit; 2.2 Distributed transaction without corresponding dba_2pc entries In this case dba_2pc views are empty but users are receiving distributed txn related errors, e.g. ORA-2054, ORA-1591. Normally such a case should not appear and if it is reproducible a bug should be filed. Here is the list of several alternative solutions that can be used in this case: a. Perform incomplete recovery b. Truncate the objects referenced by that transaction and import them c. Use _corrupted_rollback_segments parameter to drop that rollback segment d. Insert dummy entries into dba_2pc views and either commit or rollback force the distributed transaction The first three solutions are discussed in Backup and Recovery manuals and in the notes referred above. In the 4th solution a dummy entry is inserted into the dictionary so that the transaction can be manually committed or rolled back. Note that RECO will not be able to process this txn and distributed txn recovery should be disabled before using this method. Furthermore, please take a BACKUP of your database before using this method. The stranded entries is the cause of ORA-01591 so we need to clear the stranded entries by purging them using execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('transanction_id'); The following example describes how to diagnose and resolve this case. Suppose that users are receiving ORA-1591: lock held by in-doubt distributed transaction 1.92.66874 and the following query returns no rows: select local_tran_id, state from dba_2pc_pending where local_tran_id='1.92.66874'; no rows selected Furthermore querying the rollback segment shows that 1.92.66874 remains in prepared state SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */ KTUXESTA Status, KTUXECFL Flags FROM x$ktuxe WHERE ktuxesta!='INACTIVE' AND ktuxeusn= 1; /* <== Replace this value with your txn undo seg# Which is displayed in the first part of the transaction ID */ KTUXEUSN KTUXESLT KTUXESQN STATUS FLAGS ---------- ---------- ---------- ---------------- ------------------------ 1 92 66874 PREPARED SCO|COL|REV|DEAD Trying to manually commit or rollback this transaction commit force '1.92.66874'; ORA-02058: no prepared transaction found with ID 1.92.66874 raises ORA-02058 since dba_2pc views are empty. In order to use commit force or rollback force a dummy record should be inserted into pending_trans$ as follows: alter system disable distributed recovery; insert into pending_trans$ ( LOCAL_TRAN_ID, GLOBAL_TRAN_FMT, GLOBAL_ORACLE_ID, STATE, STATUS, SESSION_VECTOR, RECO_VECTOR, TYPE#, FAIL_TIME, RECO_TIME) values( '1.92.66874', /* <== Replace this with your local tran id */ 306206, /* */ 'XXXXXXX.12345.1.2.3', /* These values can be used without any */ 'prepared','P', /* modification. Most of the values are */ hextoraw( '00000001' ), /* constant. */ hextoraw( '00000000' ), /* */ 0, sysdate, sysdate ); insert into pending_sessions$ values( '1.92.66874',/* <==Replace only this with your local tran id */ 1, hextoraw('05004F003A1500000104'), 'C', 0, 30258592, '', 146 ); commit; commit force '1.92.66874'; If commit force raises an error then note the errormessage and execute the following: delete from pending_trans$ where local_tran_id='1.92.66874'; delete from pending_sessions$ where local_tran_id='1.92.66874'; commit; alter system enable distributed recovery; Otherwise run purge the dummy entry from the dictionary, using alter system enable distributed recovery; connect / as sysdba COMMIT; Use following query to retrieve the value for such _smu_debug_mod parameter: col Parameter for a20 col "Session Value" for a20 col "Instance Value" for a20 SELECT a.ksppinm "Parameter",b.ksppstvl "Session Value",c.ksppstvl "Instance Value" FROM x$ksppi a, x$ksppcv b, x$ksppsv c WHERE a.indx = b.indx AND a.indx = c.indx AND a.ksppinm = '_smu_debug_mode' / -- set it temporarily to 4: alter system set "_smu_debug_mode" = 4; /* if automatic undo management is being used */ -- in 9.2x alter session can be used instead. commit; /* this is to prevent the ORA-01453 in purge_lost_db_entry call */ exec dbms_transaction.purge_lost_db_entry( '1.92.66874' ); SQL> commit;
SQL> alter system set “_smu_debug_mode” =;
SQL> commit;
2.3 How to PURGE the DISTRIBUTED transaction in PREPARED state, when COMMIT
or ROLLBACK FORCE hangs ?, where we have entries for both Distributed
transaction and dba_2pc entries.
ORA-01591: lock held by in-doubt distributed transaction 44.88.85589
The row exist from dba_2pc_pending & Rollback segment
SQL> SELECT LOCAL_TRAN_ID,STATE FROM DBA_2PC_PENDING;
LOCAL_TRAN_ID STATE
—————– ———–
44.88.85589 prepared
SQL> SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */
KTUXESTA Status,
KTUXECFL Flags
FROM x$ktuxe
WHERE ktuxesta!=’INACTIVE’
AND ktuxeusn= 44; /* <== Replace this value with your txn undo seg# Which is displayed in the first part of the transaction ID */ KTUXEUSN KTUXESLT KTUXESQN STATUS FLAGS ---------- ---------- ---------- ---------------- ------------------------ 44 88 85589 PREPARED SCO|COL|REV|DEAD SQL> Commit force 44.88.85589;
SQL> rollback force 44.88.85589;
Executing COMMIT or ROLLBACK FORCE hangs
The wait event is “”free global transaction table entry”
Purging the transaction should fail with below error:
EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY(‘44.88.85589’);
BEGIN DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY(‘44.88.85589’); END;
*
ERROR at line 1:
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at “SYS.DBMS_TRANSACTION”, line 94
ORA-06512: at line 1
Solution:
——–
You have to implement both the solution :
2.1 Dba_2pc entries without a corresponding transaction
2.2 Distributed transaction without corresponding dba_2pc entries
1.
delete from sys.pending_trans$ where local_tran_id = ‘44.88.85589’;
delete from sys.pending_sessions$ where local_tran_id = ‘44.88.85589’;
delete from sys.pending_sub_sessions$ where local_tran_id =’44.88.85589′;
commit;
2. Now insert the dummy record as explained in section:
2.2 Distributed transaction without corresponding dba_2pc entries
commit;
3. Commit force ‘44.88.85589’
4. Purge the transaction:
exec dbms_transaction.purge_lost_db_entry(‘44.88.85589’);
Note:126069.1 Manually Resolving In-Doubt Transactions: Different Scenario’s