问题
I have an application in C# that uses an Oracle database. I need a query to fetch the unlocked row from a table in oracle database. How can I select all unlocked rows?
Is there any 'translator' out there that can translate this T-SQL (MS SQL Server) query to Oracle dialect?
SELECT TOP 1 * FROM TableXY WITH(UPDLOCK, READPAST);
I'm a little bit disappointed with Oracle lacking such a feature. They want to make me use AQ or what?
回答1:
Oracle does have this feature, specifically the SKIP LOCKED portion of the SELECT statement. To quote:
SKIP LOCKED is an alternative way to handle a contending transaction that is locking some rows of interest. Specify SKIP LOCKED to instruct the database to attempt to lock the rows specified by the WHERE clause and to skip any rows that are found to be already locked by another transaction.
The documentation goes on to say it's designed for use in multi-consumer queues but this does not mean that you have to use it in this environment. Though the documentation says this there is a large caveat. You can't ask for the next N unlocked rows - only the next N rows, of which the unlocked ones will be returned.
SELECT *
FROM TableXY
WHERE ROWNUM = 1
FOR UPDATE SKIP LOCKED
Note that if the table you're selecting from is locked in exclusive mode, i.e. you've already instructed the database not to let any other session lock the table you will not get any rows returned until the exclusive lock is released.
回答2:
I faced with the same problem recently, and after solved it, I wrote this blog entry:
http://nhisawesome.blogspot.com/2013/01/how-to-lock-first-unlocked-row-in-table.html
Feel free to leave a comment! Your comments are appreciated.
Short summary: instead of select first unlocked one and lock it, I select a bunch of records, then loop through the bunch and try to acquire a lock on it using SKIP LOCKED hint. If the selected one is not lockable, move on to the next one, until a lock acquired or none remain.
回答3:
select for update nowait will error out if you select a row that is locked. Is that what you want? I am curious as to what problem you are trying to solve. Unless you have long-running transactions, the lock on a row would be transient from one moment to the next.
Example:
CREATE TABLE TEST ( COL1 NUMBER(10) NOT NULL, COL2 VARCHAR2(20 BYTE) NOT NULL );
CREATE UNIQUE INDEX TEST_PK ON TEST (COL1);
ALTER TABLE TEST ADD ( CONSTRAINT TEST_PK PRIMARY KEY (COL1) USING INDEX TEST_PK );
SQL Session #1: SQL> insert into test values(1,'1111'); 1 row created. SQL> insert into test values(2,'2222'); 1 row created. SQL> commit; Commit complete. SQL> update test set col2='AAAA' where col1=1; 1 row updated.
SQL Session #2: Attempt to read locked row, get error:
SQL> select * from test where col1=1 for update nowait; select * from test where col1=1 for update nowait * ERROR at line 1: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
来源:https://stackoverflow.com/questions/14113744/select-unlocked-rows-oracle