File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes JDBC and the fly likes How to prevent a race condition between reading and updating Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Databases » JDBC
Bookmark "How to prevent a race condition between reading and updating" Watch "How to prevent a race condition between reading and updating" New topic
Author

How to prevent a race condition between reading and updating

N Carlo
Greenhorn

Joined: May 15, 2009
Posts: 13
Hi all,

I am having trouble preventing a race condition in a J2EE app that accesses an Oracle database. The sequence of events goes like this:

1) My servlet receives a request.
2) The servlet checks the value of a flag stored in the database.
3) If the flag is set to 'N' then it sets it to 'Y', and performs some other actions that must only be done once.

The problem occurs when I have multiple simultaneous requests (which is common for this particular service). For example:

Thread 1 checks the flag and sees that it is N.
Thread 2 checks the flag and sees that it is N.

Thread 1 updates the flag to Y and does the stuff that should only be done once.
Thread 2 also updates the flag to Y and proceeds to duplicate the work that should only be done once.

What I want is to prevent Thread 2 from reading the flag until after Thread 1 has had a chance to update it. What is the best way to do this in JDBC? I thought about using transactions, but I wasn't sure if that would provide the intended functionality. Any and all help is greatly appreciated.
Scott Selikoff
author
Saloon Keeper

Joined: Oct 23, 2005
Posts: 3710
    
    5

Generally you use transactions to avoid this type of behavior. The first process to commit will finish without issue, whereas the second process will likely get a stale data exception and be required to start over. Alternatively, you could go with a Java Singleton pattern to allow only one thread into a process although its not really a J2EE application if only one person can use it at a time. Granted, single-threading may be what you want in this case.


My Blog: Down Home Country Coding with Scott Selikoff
Fatih Keles
Ranch Hand

Joined: Sep 01, 2005
Posts: 182
Oracle apps uses object version number on many tables. Also I have seen it on some ORM software. Each update on a row increases OVN by one -either with trigger or programmatically. So once you get the row for update you have an OVN then when you are updating you also provide OVN+1 and expect that to be equal to OVN+1 on the row. If not then the row data has been changed by some one since your last fetch.

Since this kind of solution can be implemented most easily by triggers, triggers also bring a burden on execution time but I guess the least among others. But also increases vendor dependencies.

Just a thought to be considered.

Regards,

Fatih.
N Carlo
Greenhorn

Joined: May 15, 2009
Posts: 13
One thing I am not clear on is how to use a transaction to prevent this race condition. My understanding is that a transaction will lock the row for writing, but not for reading. So, how do I prevent Thread 2 from reading the value before Thread 1 updates it? Any code samples of how to prevent this with a transaction would be greatly appreciated. I also tried using SELECT FOR UPDATE but I still get the race condition. Here is some code to illustrate my current approach, which is not working. I'm not sure if I need to roll back on line 30, but I wanted to make sure that nothing would stay locked.



Alok Bhandari
Greenhorn

Joined: Jun 11, 2008
Posts: 15
Hello ,
I am also facing the same issue ,have you found the solutions.Any help is appreciated.


SCJP 1.6(98%)
Sudheer Bhat
Ranch Hand

Joined: Feb 22, 2011
Posts: 75
I am surprised that select for update is not working for you. Select for update acquires the exclusive lock on the rows selected. Thus the read will not happen if the lock is not acquired. Thus at any point of time only one session/transaction can hold the lock. The other SELECT FOR UPDATE should simply wait for the lock to be released (either by commit or rollback). If you specify SELECT FOR UPDATE NOWAIT then the second thread should simply throw an ORA error(ORA-00054) and exit.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: How to prevent a race condition between reading and updating