0

This post is somewhat related to this post of mine: How to synchronize database access in a WCF Service?

The responses I got there were over-complicated and \ or contradicting ... :(

I have created a sample WCF service, and I run 3 instances of clients against it. The service communicates with an SQL table called names, with several rows.

One client spawns function 1 in the service.

The second client spawns function 2 in the service.

function1 spawns a function on the service that :

a. Changes a specific row from 'Charlie' to 'Chin'

b. waits 5 seconds

c. changes the row again from 'Chin' to 'Carol'

function2 spawns a function that returns a list of all the names.

It is important to note that both functions in the service are wrapped with 'TransactionScope'.

What I do: I run function1 (which changes 'Charlie' to 'Chin' and waits for 5 seconds), then immediatly I spawn function2 which tries to get the list of names but hangs (because function1 hasn't finished yet), and after couple of seconds function1 changes the name from 'Chin' to 'Carol' and only then function2 is released and it returns the list of names.

The things is - the list of names that is returned from function2 doesn't contain 'Carol' ! it contains 'Charlie' ! Why is this ? I thought that because function2 hanged until function1 finished - it would also fetch the data only when function1 finished, but apparently this is not the case.

What am I doing wrong ?

I do not want to start using locks, because this would slow the whole system down. I will have approximately 20 methods in my final service, and I don't want all of them to have to use locks... (only 3-4 methods are for 'reading', but they are the ones that will be used 95% of the time)...

Community
  • 1
  • 1
John Miner
  • 893
  • 1
  • 15
  • 32

1 Answers1

0

To do this you need to lock the data that is being changed such that the other process cannot read the data until the first process is complete.

You use the TransactionScope to do this. Set the isolation level to serializable. This will lock the data. You may have to specify that the read also updates the data (to the same values) to get the second call to wait.

http://msdn.microsoft.com/en-us/library/system.transactions.isolationlevel(v=vs.90).aspx

Shiraz Bhaiji
  • 64,065
  • 34
  • 143
  • 252
  • In the link you supplied it says 'By default, the System.Transactions infrastructure creates Serializable transactions.'. This means that 'The highest isolation level, Serializable, provides a high degree of protection against interruptive transactions, but requires that each transaction complete before any other transactions are allowed to operate on the data.' But this is not the behavior I saw. Indeed - 'Function 2' halted and waited till 'Function 1' finished, but the data it actually read was the data that was before 'Function 1's changes ! it should have shown a fresh set of data ! – John Miner Apr 17 '12 at 20:41
  • UPDATE : I now see that I forgot to do 'transaction.Complete();'. Stupid me ... :) I now see that it is enough to only wrap 'Function 1' with a transaction scope, and this makes 'Function 2' get the right information (it waits till function 1 finishes) even though 'Function 2' doesn't have a transaction scope ! this is great ! Can you tell me why this is ? and what happens if I have called 'Function 2' from 2 different clients ? which one will fire first when 'Function 1' finishes ? first-come-first-served ? – John Miner Apr 17 '12 at 20:53