views:

108

answers:

4

Hi all,

I'm interested in whether a select for update query will lock a non-existent row.

e.g.

Table FooBar with two columns, foo and bar, foo has a unique index

  • Issue query select bar from FooBar where foo = ? for update
  • If query returns zero rows
    • Issue query insert into FooBar (foo, bar) values (?, ?)

Now is it possible that the insert would cause an index violation or does the select for update prevent that?

Interested in behaviour on SQLServer(2005/8), Oracle and MySQL.

+4  A: 

In Oracle, the SELECT ... FOR UPDATE has no effect on a non-existent row (the statement simply raises a No Data Found exception). The INSERT statement will prevent a duplicates of unique/primary key values. Any other transactions attempting to insert the same key values will block until the first transaction commits (at which time the blocked transaction will get a duplicate key error) or rolls back (at which time the blocked transaction continues).

DCookie
I would restate the part about "the statement simply raises a non data found exception"; a SELECT...FOR UPDATE could return rows and still have no effect on a non-existent row. ;)
Patrick Marchand
Not in the case the OP stated, where the select was on foo=explicit_value, foo being uniquely indexed.
DCookie
It is possible for SELECT statement to return 0 rows. It only raises NO_DATA_FOUND if it is invoked with INTO.
jva
Point taken. I was looking at the pseudocode and translating to a procedural context.
DCookie
A: 

SQL Server only has the FOR UPDATE as part of a cursor. And, it only applies to UPDATE statements that are associated with the current row in the cursor.

So, the FOR UPDATE has no relationship with INSERT. Therefore, I think your answer is that it's not applicable in SQL Server.

Now, it may be possible to simulate the FOR UPDATE behavior with transactions and locking strategies. But, that may be more than what you're looking for.

bobs
Historically, there may have been a difference in behavior (when updates locked the whole table) - but not in the last decade (and quite possibly, not since FOR UPDATE was introduced).
JulesLt
+1  A: 

I wrote a detailed analysis of this thing on SQL Server: Developing Modifications that Survive Concurrency

ANyway, you need to use SERIALIZABLE isolation level, and you really need to stress test.

AlexKuznetsov
+1  A: 

On Oracle:

Session 1

create table t (id number);
alter table t add constraint pk primary key(id);

SELECT *
FROM t
WHERE id = 1
FOR UPDATE;
-- 0 rows returned
-- this creates row level lock on table, preventing others from locking table in exclusive mode

Session 2

SELECT *
FROM t 
FOR UPDATE;
-- 0 rows returned
-- there are no problems with locking here

rollback; -- releases lock


INSERT INTO t
VALUES (1);
-- 1 row inserted without problems
jva