提问者:小点点

隔离对于从WCF客户端传播到WCF服务的事务有什么意义?


这个问题有三个部分:

  1. 为什么Serializable事务不原子地执行操作?
  2. 假设答案是事务的原子性并不能保证其组成操作的原子性(并且它只确保所有操作要么全部成功,要么全部失败),为什么事务的隔离要求不能确保操作是原子的?我读过Serializable隔离级别确保事务像串行执行一样执行?
  3. 如果我对隔离的解释不正确,正确的解释是什么,我如何修改测试以证明使用序列化事务与根本不使用事务之间的区别。

代码可以从这里下载

假设DataLayer(DAL)由WCF服务实现,并且客户端代码由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();
            }
        }
    }

还假设:

  1. 客户端和服务配置正确,可以将客户端事务传播到服务。(通过观察存在环境事务,它具有分布式标识符并且标识符与客户端相同,在服务端验证了这一点。
  2. 事务的隔离模式(在服务和客户端)是Serializable(通过观察服务和客户端上环境事务的属性进行验证)

同时运行两个客户端进程。

预期结果是,两个客户端退出后的账户余额应该比两个客户端启动前大20000。

两个客户端退出后的帐户余额是10000到20000之间的值。在某些情况下,其中一个客户端因以下错误而中止:

事务(进程ID)在锁资源上与另一个进程死锁,并被选为死锁受害者

每个客户端上的TransactionScope范围内包含的操作并不与其他客户端的操作作为一个整体串联运行。来自两个事务的读取和写入混合在一起,并且丢失了一些增量。


共1个答案

匿名用户

    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");
        }
    }

当然,这是非常低效的,但它按预期工作,并演示了事务如何隔离资源管理器上的操作。