Question : Multi-threading and row locking on selects

Hi there,

this is a fairly general question and a few pointers, examples or links to tutorials would be great.

I had designed a database that is deployed in a multi-threaded Java environment. Basically, there is java services that are constantly running over the database, checking for new records, updating them etc.

I have implemented Store Procs for all the updates, gets etc and have everything wrapped inside transactions inside the store proc. So far so good.  However my main concern is how do I stop a record or maybe a records in a few tables getting updated between the time I 'Select' data from them to the time I actually update the record and commit the transaction. As far as I'm aware the transaction doesnt kick in, until an update, delete or insert is called inside the BEGIN Trans clause.

So an example would be

Table Account has 2 records like so
AccID, Account Name, Balance
1020,  John Smith, €-128.00
1057, Mike Reed, €5839,00

I have a few services running over these tables looking to do different tasks on the records.
John Smith is in the red, but a wire has come through for some funds so the Service update funds is going to add €1000 into his account.
In my stor proc I want add a record for the funds added to one table and update the Account table. I Begin a transaction. So then I do a select Balance from Account and get €-128.  I then create the wire record in the WireDetails table and go to update the balance in the accounts.

How do I stop another serivice coming in and making changes to the account table, as I only have selected from it.

Sorry for the silly example but I hope you see what it is that I,m trying to stop...
thanks M

Answer : Multi-threading and row locking on selects

Let's say you have table t(i int not null, a char(1))
insert into t select 1,'a'

thread A1 issues this:

begin transaction
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
select * from t where i=2


and then just sits there. Along comes thread B and issues

select * from t where i=2
update t set a='c' where i=2


The 1st of these B's statements will succeed, but the 2nd one will wait until thread A has issued commit. There's a problem however: it's easy to see that B can easily override the change made by A, if he acts basing on what he sees when he has retrieved the row. For that reason, it's better to issue

update t set a='c' where i=2 and a='a'

This effectively verifies that B is updating what he thinks he is updating. And this is exactly how client-based cursor is working, which is the most usual type of the cursor used in today's development tools, especially web-based: no transaction, no lock, but during the update verification of all the fields that were read, and if any has changed, then error message to the effect that another user has modified the resultset.

If you want to eliminate this, then you have to issue even more restrictive transaction isolation level SERIALIZABLE in the thread B, and as soon as you read the rows in A, update them there by using some dummy column just for this purpose. Then B won't be able to see the rows that may be modified by A - which is correct, because otherwise B wouldn't know that these rows are now being worked on by A. But this of course brings in the issue of A crashing, leaving for lunch, etc, etc.

For that reason, client-located cursor is probably the most practical way to do all this, which is why it's the most widespread type of database operations today.
Random Solutions  
 
programming4us programming4us