I need to update a row in an Oracle database in a way that I don’t silently clobber the changes from another client in my web based application.
In my current system I perform the following:
SELECT * FROM table WHERE id=:ID AND lastmodified=:LASTMOD
if the row still exists with the same last modified date when we started we know nobody has changed it so we can update using the last modified time.
However when doing this manually using two sessions I noticed if two clients select at roughly the same time its possible for one to miss that the row has been changed between the select and update step due to both occurring within the same second or millisecond.
The end result is that I clobber the changes of the other user and there is no warning that it occurred.
I was thinking of using SELECT FROM UPDATE but apparently that’s a bad idea (especially for web apps), the article recommends re-reading (which is what I’m doing above) but I still think I’m at risk of a race condition.
Edit: Made it clear I was concerned about the way time is referenced.
I’m assuming that your
UPDATEstatement itself is verifying thelastmodifiedvalue that you read in yourSELECTstatement as ninesided suggests.If
lastmodifiedis aDATE, then there is a potential race condition if there are multiple updates to the same row in the same second since aDATEonly has granularity to the second. Iflastmodifiedis aTIMESTAMP, on the other hand, the window in which the race condition can occur is much more limited since aTIMESTAMPwill have between 3 and 9 digits of sub-second precision (3 on most Windows machines, 6 on most Unix machines). It’s pretty unlikely though not impossible that you’d have two updates at the same millisecond or even the same microsecond. But it’s not infallible.You can use a sequence-generated value instead of a last modified date. That can guarantee that you won’t lose an update since a NOCYCLE sequence won’t return the same value twice. But if you go down that path, you’re either losing the information benefit of having a last update date on every row or you’re storing a few extra bytes of data in every row of the table. Either of those trade-offs may be worth it depending on your application or either might create more problems than it resolves.