Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.misc -> Re: Effective deadlock handling

Re: Effective deadlock handling

From: Daniel Morgan <damorgan_at_x.washington.edu>
Date: Tue, 06 Jan 2004 11:17:24 -0800
Message-ID: <1073416558.103354@yasure>


Erik wrote:

> This was a long thread, and I didn't feel like reading it all to see if
> someone
> has solved the problem. The problem is in the code:
>
>

>>UPDATE job_stats
>>SET    NUM_CANCELLED = NUM_CANCELLED - 1
>>WHERE  per_id = p_per_id
>>AND    job_date = p_old_date;
>>
>>UPDATE job_stats
>>SET    NUM_BOOKED = NUM_BOOKED + 1
>>WHERE  per_id = p_per_id
>>AND    job_date = p_new_date;

>
>
> Say job_stats contains three rows:
> (1) per_id = 10, job_date = '2004-01-01' and
> (2) per_id = 10, job_date = '2004-01-02'
>
> Now, thread #1 calls the procedure with
> p_per_id = 10, p_old_date = '2004-01-01' and p_new_date = '2004-01-02'
>
> and slightly afterwards (before the second UPDATE is started), thread #2
> calls it with
> p_per_id = 10, p_old_date = '2004-01-02' and p_new_date = '2004-01-01'.
>
> Now, what will happen is:
> 1. Thread #1 locks row (1) with the first UPDATE statement
> 2. Thread #2 locks row (2) with the first UPDATE statement
> 3. Thread #1 tries to lock row (2), with the second UPDATE, but this row is
> locked by thread #2, so thread #1 is waiting for the lock to be
> released.
> 4. Thread #2 tries to lock row (1) with the second UPDATE, but this row is
> locked by thread #1, so Oracle detects a deadlock.
>
> So what to do about it? The rows must be locked at the same time. I can
> think
> of two obvious ways to do this:
>
> 1: Lock both rows at the same time by doing something like this before the
> first UPDATE:
> CURSOR c IS SELECT job_date FROM job_stats
> WHERE per_id = p_per_id AND job_date IN(p_new_date, p_old_date)
> FOR UPDATE OF num_cancelled, num_booked;
> OPEN c;
>
> 2: Do both updates within the same statement, like
> UPDATE job_stats SET
> num_booked =
> CASE WHEN job_date = p_new_date THEN
> num_booked + 1
> ELSE
> num_booked
> END,
> num_cancelled =
> CASE WHEN job_date = p_old_date THEN
> num_cancelled + 1
> ELSE
> num_cancelled
> END
> WHERE per_id = 10 AND job_date IN(p_old_date, p_new_date)
>
> / Erik

I think the problem has always been easily solvable using defensive programming and examples similar to yours using FOR UPDATE have been suggested.

What appears to be keeping this thread alive, prior to your contribution was a combination of testosterone and technology. Always an unsightly mixture.

-- 
Daniel Morgan
http://www.outreach.washington.edu/ext/certificates/oad/oad_crs.asp
http://www.outreach.washington.edu/ext/certificates/aoa/aoa_crs.asp
damorgan_at_x.washington.edu
(replace 'x' with a 'u' to reply)
Received on Tue Jan 06 2004 - 13:17:24 CST

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US