views:

1694

answers:

5

Is there a way to exclusively lock a table for reading in Oracle (10g) ? I am not very familiar with Oracle, so I asked the DBA and he said it's impossible to lock a table for reading in Oracle?

I am actually looking for something like the SQL Server (TABLOCKX HOLDLOCK) hints.

EDIT:

In response to some of the answers: the reason I need to lock a table for reading is to implement a queue that can be read by multiple clients, but it should be impossible for 2 clients to read the same record. So what actually happens is:

  1. Lock table
  2. Read next item in queue
  3. Remove item from the queue
  4. Remove table lock

Maybe there's another way of doing this (more efficiently)?

A: 

If you mean, lock a table so that no other session can read from the table, then no, you can't. Why would you want to do that anyway?

Tony Andrews
See my edit. I may be missing something obvious...
Philippe Leybaert
+11  A: 

If you just want to prevent any other session from modifying the data you can issue

LOCK TABLE whatever
/

This blocks other sessions from updating the data but we cannot block other peple from reading it.

Note that in Oracle such table locking is rarely required, because Oracle operates a policy of read consistency. Which means if we run a query that takes fifteen minutes to run the last row returned will be consistent with the first row; in other words, if the result set had been sorted in reverse order we would still see exactly the same rows.

edit

If you want to implement a queue (without actually using Oracle's built-in Advanced Queueing functionality) then SELECT ... FOR UPDATE is the way to go. This construct allows one session to select and lock one or more rows. Other sessions can update the unlocked rows. However, implementing a genuine queue is quite cumbersome, unless you are using 11g. It is only in the latest version that Oracle have supported the SKIP LOCKED clause. Find out more.

APC
See the edit I made to my question
Philippe Leybaert
+1, this is how I'd do it; good links.
DCookie
+2  A: 

The TABLOCKX and HOLDLOCK hints you mentioned appear to be used for writes, not reads (based on http://www.tek-tips.com/faqs.cfm?fid=3141). If that's what you're after, would a SELECT FOR UPDATE fit your need?

UPDATE: Based on your update, SELECT FOR UPDATE should work, assuming all clients use it.

UPDATE 2: You may not be in a position to do anything about it right now, but this sort of problem is actually an ideal fit for something other than a relational database, such as AMQP.

Hank Gay
TABLOCKX will lock the table exclusively (no other client can lock the table when another client has a TABLOCKX lock on it). This effectively prevents other clients from reading the table (if they also request the lock of course)
Philippe Leybaert
Generally speaking, Oracle doesn't lock on reads.
Hank Gay
+2  A: 
   1. Lock table
   2. Read next item in queue
   3. Remove item from the queue
   4. Remove table lock

Under this model a lot of sessions are going to be doing nothing but waiting for the lock, which seems a waste. Advanced Queuing would be a better solution.

If you want a 'roll-your-own' solution, you can look into SKIP LOCKED. It wasn't documented until 11g, but it is present in 10g. In this algorithm you would do

   1. SELECT item FROM queue WHERE ... FOR UPDATE SKIP LOCKED
   2. Process item
   3. Delete the item from the queue
   4. COMMIT

That would allow multiple processes to consume items off the queue.

Gary
I don't think that SKIP LOCKED clause is usable that way. select for update performs a "normal" select and (conceptually) than it locks the selected rows. With SKIP LOCKED you just don't hang at the try to lock selected rows and lock only the ones you can. Don't see how this can help here (2 sessions issuing the "same" select ends with one locking all selected rows and the second locking and returning 0 rows)
Michal Pravda
A: 

Oracle provide that functionality already in their Advanced Queueing interface. I would be looking at that first.

David Aldridge