简体   繁体   中英

What is the meaning of Isolation for a transaction that propagates from WCF client to WCF service?

Question

There are three parts to this question:

  1. Why does a Serializable transaction not perform operations atomically?
  2. Assuming that the answer is that atomicity of a transaction does not guarantee atomicity of its constituent operations (and that it only ensures that all operations either all succeed or all fail), why does the Isolation requirement of the transaction not ensure that the operations are atomic? I have read that the Serializable isolation level ensures that transactions are executed as if they were executed serially?
  3. If my interpretation of Isolation is not correct, what is the correct interpretation 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.

A Minimal Complete and Verifiable example

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:

  1. The client and the service are configured correctly to propagate client transactions to the service. (This was verified on the service side by observing that there is an ambient transaction, that it has a distributed identifier and that the identifier is the same as the one on the client side.
  2. The isolation mode of the transaction (both in the service and on the client) is Serializable (verified by observing the properties of the ambient Transaction on service and client)

Test Description

Run two client processes concurrently.

Expected Result

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.

Actual Result

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

Conclusion

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.

  1. Question : "Why does a Serializable transaction not perform operations atomically"
    Answer : A Serializable transaction is atomic in the sense that all its operations will either all succeed or all fail. This is not refuted by the example.
  2. Question : "Why does the Isolation requirement of the transaction not ensure that the operations are atomic?
    Answer : Two Serializable transactions meet the Isolation requirement in that they will not run concurrently. If two try to run together, one will continue as planned and the other is aborted. This is precisely why the exception that is reported in the question occurred. ("Transaction (Process ID) was deadlocked on lock resources with another process and has been chosen as the deadlock victim").
  3. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM