There are three parts to this question:
The code can be downloaded from here
Assume that the DataLayer (DAL) is implemented by a WCF service and that the client side code consists of a call to its operations from Main:
public void Main(string[] args)
{
var dal = new DataLayerServiceClient();
var accounts = dal.GetAccounts();
int accountId = accounts.First().AccountId;
for (int i = 0; i < 10000; i++)
{
using (TransactionScope scope = new TransactionScope())
{
var account = dal.GetAccountById(accountId);
account.Balance++;
dal.Update(account);
scope.Complete();
}
}
}
Assume also:
Run two client processes concurrently.
The expected result is that the balance of the account after both clients exit should be 20000 larger than it was before both clients started.
The balance of the account after both clients exit is a value between 10000 and 20000. In some cases, one of the client is aborted due to the following error:
Transaction (Process ID) was deadlocked on lock resources with another process and has been chosen as the deadlock victim
The operations contained within the scope of the TransactionScope on each client did not run as a whole in series with those of the other client. Reads and writes from both transactions were mixed and some of the increments were lost.
Question : "If my interpretation of Isolation is not correct, what is the correct interpretation?".
Answer : The incorrect assumption in the question is that if two transactions cannot run concurrently, one will wait for the other to complete and then proceed. This is not correct. Indeed Serializable transactions are isolated and will not run concurrently, but that does not mean that one will wait for the other. Isolation of transactions is not the same as holding a mutex in order to perform a set of operations in isolation.
Question : "and how could I modify the test to demonstrate the difference between the use of Serialized transaction as oppose to not using a transaction at all"
Answer : The following snippet would demonstrate the use of transactions to assure that increment occurs as expected.
int i = 0; while(i < 10000) { try { using (TransactionScope scope = new TransactionScope()) { var account = dal.GetAccountById(accountId); account.Balance++; dal.Update(account); scope.Complete(); } i++; } catch (Exception ex) { Console.WriteLine($"{ex.Message} : restarting"); } }
Of course this is extremely inefficient but it works as expected and demonstrates how transactions isolate operations on resource managers.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.