none
关于客户端和服务端之间事务的问题 RRS feed

  • 问题

  • 客户端代码如下,首先调用服务端某个方法,然后调用本地方法,假设本地方法出错,那么希望回滚服务端的事务。(服务端msdtc已开启)

     using (TransactionScope tc = new TransactionScope())
                        {
                            try
                            {
                                call service method
                                call local method
                                tc.Complete();

                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e.Message);
                                System.Transactions.Transaction.Current.Rollback();
                            }
                        
                           
                        }


    服务端方法上有2个属性
     [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]

    如果把TransactionAutoComplete设置为true,那么以上的代码是无法成功的,因为服务端方法调用完毕以后,自动提交事务,无论客户端接下来做什么,事务已经提交了,无法回滚。

    现在我们看TransactionAutoComplete为false的情况,据我测试,当false的时候,服务端方法结束以后,事务一直没有关闭,如果是update一个表,那么该表始终处于锁定状态,阻塞其他线程对他的操作。而无论客户端使用tc.complete还是 System.Transactions.Transaction.Current.Rollback(),服务端事务都不会结束,一直阻塞在那里直到数据库超时自动释放事务。

    msdn上有一篇文章http://msdn.microsoft.com/en-us/library/ms751413.aspx ,上面提到了服务端用一个方法 OperationContext.Current.SetTransactionComplete();来实现未提交事务的提交,我测试了一下是有效的,也就是说当客户端其他操作完毕,没有任何异常的时候再去调一下服务端的另外一个方法(在同个事务上下文里),执行这句语句,那么之前的未提交的事务会被提交。但是这里有2问题:

    1.为什么要以这种方式来提交事务,明明是一次调用的问题现在变成2次调用。之前客户端的complete为什么不起作用?
    2.我只找到了SetTransactionComplete方法,并没有提供rollback方法,如果想要回滚之前的事务应该怎么做?


    另外还有个问题,TransactionAutoComplete这个属性设置为false的时候,服务端方法的ConcurrencyMode属性必须是single,否则启动服务时微软会提示错误,不知道为什么会有这样的限制?



    they say nothing last forever
    2009年9月6日 19:11

答案

  • 你好,
    谢谢你的代码.有两点需要注意:

    1. 你当前的设置为下表的最后一种情况,即服务器使用客户端的Transaction.这样一来,如果设置TransactionAutoComplete=false, 那么Transaction不会自动结束.请去掉这个attribute.
    Binding Transaction FlowTransaction- FlowOptionTransaction- ScopeRequiredTransaction Mode
    False Allowed False None
    False Allowed True Service
    False NotAllowed False None
    False NotAllowed True Service
    True Allowed False None
    True Allowed True Client/Service
    True Mandatory False None
    True Mandatory True Client

    2. 在你的例子中, Transaction完成要在TransactionScope对象被Dispose掉以后才能递交.客户端代码请改为:

     

    using (TransactionScope tc = new TransactionScope())

    {

     

    try

    {

     

    Console.WriteLine(cl.DoWork());

     

     

    //cl.DoTran();

    tc.Complete();

    //completetimeout

    }

     

    catch (Exception e)

    {

     

    Console.WriteLine(e.Message);

    System.Transactions.

    Transaction.Current.Rollback();

    }

     

    }

     

    Console.ReadLine();



    最后,推荐这篇文章:
    http://msdn.microsoft.com/en-us/magazine/cc163432.aspx
    Please remember to mark the replies as answers if they help and unmark them if they provide no help. Welcome to the All-In-One Code Framework http://cfx.codeplex.com/! If you have any feedback, please tell us.
    2009年9月10日 3:54
    版主

全部回复

  • 你好,
    请问TransactionFlow开启了吗?
    http://msdn.microsoft.com/en-us/library/ms730232.aspx
    Please remember to mark the replies as answers if they help and unmark them if they provide no help. Need a sample of a technique of Microsoft? Just check out CodeFx first! http://cfx.codeplex.com/
    2009年9月8日 2:11
    版主
  • 是的,服务端的operation contract上已经定义了[TransactionFlow(TransactionFlowOption.Mandatory)]

    我现在把local操作去掉,仅仅调服务器端的方法并且提交事务:

    try
                            {
                                call service method
                                       tc.Complete();


                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e.Message);
                                System.Transactions.Transaction.Current.Rollback();
                            }

    当服务器端成功执行数据更新的方法并且返回值以后,在客户端提交complete之前,服务器端的数据表被阻塞,而当complete执行完以后,很搞笑的,服务器端的表数据被回滚了,更新失败。而客户端抛出一个事务已终止的异常。


    they say nothing last forever
    2009年9月8日 20:47
  • 你好,
    这样吧,你先在同一台机器上启动服务器端和客户端程序测试一下(数据库也是在同一台机器).如果还是这样请提供一个demo项目,我来测试下看看.项目可以上传到http://skydrive.live.com/然后在这里贴一下链接.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help. Need a sample of a technique of Microsoft? Just check out CodeFx first! http://cfx.codeplex.com/
    2009年9月9日 1:49
    版主
  • 我的客户端,服务端,数据库本就是同一台机器。

    我已经将代码传到http://cid-5885dec9ca676082.skydrive.live.com/self.aspx/.Public/WCFTran.rar
    请试试能否下载,感谢!
    they say nothing last forever
    2009年9月9日 17:08
  • 你好,
    谢谢你的代码.有两点需要注意:

    1. 你当前的设置为下表的最后一种情况,即服务器使用客户端的Transaction.这样一来,如果设置TransactionAutoComplete=false, 那么Transaction不会自动结束.请去掉这个attribute.
    Binding Transaction FlowTransaction- FlowOptionTransaction- ScopeRequiredTransaction Mode
    False Allowed False None
    False Allowed True Service
    False NotAllowed False None
    False NotAllowed True Service
    True Allowed False None
    True Allowed True Client/Service
    True Mandatory False None
    True Mandatory True Client

    2. 在你的例子中, Transaction完成要在TransactionScope对象被Dispose掉以后才能递交.客户端代码请改为:

     

    using (TransactionScope tc = new TransactionScope())

    {

     

    try

    {

     

    Console.WriteLine(cl.DoWork());

     

     

    //cl.DoTran();

    tc.Complete();

    //completetimeout

    }

     

    catch (Exception e)

    {

     

    Console.WriteLine(e.Message);

    System.Transactions.

    Transaction.Current.Rollback();

    }

     

    }

     

    Console.ReadLine();



    最后,推荐这篇文章:
    http://msdn.microsoft.com/en-us/magazine/cc163432.aspx
    Please remember to mark the replies as answers if they help and unmark them if they provide no help. Welcome to the All-In-One Code Framework http://cfx.codeplex.com/! If you have any feedback, please tell us.
    2009年9月10日 3:54
    版主

  • Allen你好,根据你说的调整了一下代码,现在看起来似乎没有问题,非常感谢!



    they say nothing last forever
    2009年9月10日 17:43