Developing solutions that base on a concurrent access and modification of the data is always a very sensible thing. They're also prone to errors that happen very rarely and are hard to find.
In your case, what you want to do is to, in fact, serialize access to your table, not only updates. That is, allow only one thread (transaction) to fetch the data it needs (where DirtyBit
is UnUsed
and Owner
is NULL
) and mark those rows as "used". I'm quite sure that your current solution doesn't work properly. Why? Consider such a scenario:
- transaction 1 begins
- transaction 2 begins
- transaction 1 reads the data from table
- transaction 2 reads the data from table - it is allowed to in shared lock mode. It reads the same data as transaction 1 did
- transaction 1 updates the table
- transaction 2 wants to update the table, but it's blocked by transaction 1 - it holds
- transaction 1 commits
- now transaction 2 may update the data and commit them
As a result both transactions 1 and 2 read the same rows and your script on both servers will operate on them. You may easily reproduce such a scenario manually operating on the database.
You can avoid it explicitly acquiring exclusive table lock. This would look like this:
begin transaction;
select * from test where DirtyBit = 'UnUsed' and Owner is null (TABLOCKX);
update test set DirtyBit = 'Used', Owner = 'Server1' where id in (...);
commit;
Here, the (TABLOCKX)
will cause the other transactions to wait until this transaction commits or rollbacks - they will not be able to read the data. Does this solve your problem?
But... if you can avoid concurrency in this specific case, I'd recommend you to do so (because of the first paragraph of my response).