none
单机换集群,lock 锁怎么办? RRS feed

  • 问题

  • 一般在单服务器下,我们可以使用Lock对代码段进行锁定,以防出现并发情况。

    lock(obj)

    {

    //do something;

    }

    然后,现在公司换集群了,也就是说,A服务器的lock与B服务器的lock是互不相认的,即使A锁住了,B服务器照样可行。

    目前我找到的方法有:

    1、EF的乐观并发,可以加Timestamp字段或者在edmx上对字段加Concurrency Mode属性设置为Fixed 处理,但是这种方法,有一方会成为牺牲者,抛出异常,程序可以捕捉异常以做Storewins 或者 ClientWins处理。

    2、使用事务,TransactionScope 并且设置最高隔离级别 Serializable 提供针对中断的事务的高度保护,

    System.Transactions.IsolationLevel.Serializable,但这种方法也是最终以一方作为牺牲者为代价来作并发控制的。

    我想要是效果:

    像Lock那样,一方在做修改的时候,另一方在等待,直到前者完成了,后者再做处理,也就是“悲观并发”。


    • 已编辑 WayneChan 2014年7月10日 3:08 完善文字描述
    2014年7月10日 3:06

答案

  • 你好:

    如果想要实现悲观锁的话,一般需要借助数据库的锁机制。据我所知,EF也没有提供悲观并发控制的机制,应用层面的控制都不是太可靠的。对于Sql Server数据库可以设置事务隔离级别为Repeatable Read来达到悲观锁的目的。

    示例代码:

    using (var scope = 
    
        new TransactionScope(TransactionScopeOption.Required, 
    
        new TransactionOptions() { IsolationLevel = IsolationLevel.RepeatableRead }))
    
    {
    
        using (var context = new NorthwindEntities())
    
        {
    
            // uncomment next line to prevent distributed transaction promotion 
    
            // on SQL Server previous to 2008
    
            // contex.Connection.Open(); 
    
            var firstCategory = context.Categories.First();
    
            var secondCategory = 
    
                context.Categories
    
                .Where(c => c.CategoryID != firstCategory.CategoryID)
    
                .First();
    
            var product = 
    
                context.Products
    
                .Where(p => p.Categories.CategoryID == firstCategory.CategoryID)
    
                .First();
    
            product.Categories = secondCategory;
    
            context.SaveChanges();
    
            scope.Complete();
    
        }
    
    }

    参考这篇博客:

    http://www.cnblogs.com/ego/articles/1456317.html

    或者通过SQL来对数据库加锁:

    using (var scope = new TransactionScope(...))
    {
        using (var context = new YourContext(...))
        {
            var customer = 
                context.ExecuteStoreQuery<Customer>("SELECT ... FROM Customers WITH (UPDLOCK) WHERE ...");
    
            // rest of your logic while record is locked
    
            scope.Complete();
        }
    }


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    2014年7月11日 6:42
    版主
  • 楼主:

    你或许只能考虑使用数据库,因为只有数据库才是两台或者多台服务器共享的;lock仅仅是内存,恐怕无法实现。

    数据库设计的时候,你可以考虑用悲观机制:

    Begin Transcation
      '查询语句,查询某些符合条件的记录
      '如果找到,进行更新等操作
      '否则先处理新数据
    End

    多个服务器调用,保证一定是按照顺序的。


    ASP.NET Forum
    Other Discussion Forums
    FreeRice Donate
    Issues to report
    Free Tech Books Search and Download

    2014年7月19日 8:16
    版主

全部回复

  • 你好:

    如果想要实现悲观锁的话,一般需要借助数据库的锁机制。据我所知,EF也没有提供悲观并发控制的机制,应用层面的控制都不是太可靠的。对于Sql Server数据库可以设置事务隔离级别为Repeatable Read来达到悲观锁的目的。

    示例代码:

    using (var scope = 
    
        new TransactionScope(TransactionScopeOption.Required, 
    
        new TransactionOptions() { IsolationLevel = IsolationLevel.RepeatableRead }))
    
    {
    
        using (var context = new NorthwindEntities())
    
        {
    
            // uncomment next line to prevent distributed transaction promotion 
    
            // on SQL Server previous to 2008
    
            // contex.Connection.Open(); 
    
            var firstCategory = context.Categories.First();
    
            var secondCategory = 
    
                context.Categories
    
                .Where(c => c.CategoryID != firstCategory.CategoryID)
    
                .First();
    
            var product = 
    
                context.Products
    
                .Where(p => p.Categories.CategoryID == firstCategory.CategoryID)
    
                .First();
    
            product.Categories = secondCategory;
    
            context.SaveChanges();
    
            scope.Complete();
    
        }
    
    }

    参考这篇博客:

    http://www.cnblogs.com/ego/articles/1456317.html

    或者通过SQL来对数据库加锁:

    using (var scope = new TransactionScope(...))
    {
        using (var context = new YourContext(...))
        {
            var customer = 
                context.ExecuteStoreQuery<Customer>("SELECT ... FROM Customers WITH (UPDLOCK) WHERE ...");
    
            // rest of your logic while record is locked
    
            scope.Complete();
        }
    }


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    2014年7月11日 6:42
    版主
  • 楼主:

    你或许只能考虑使用数据库,因为只有数据库才是两台或者多台服务器共享的;lock仅仅是内存,恐怕无法实现。

    数据库设计的时候,你可以考虑用悲观机制:

    Begin Transcation
      '查询语句,查询某些符合条件的记录
      '如果找到,进行更新等操作
      '否则先处理新数据
    End

    多个服务器调用,保证一定是按照顺序的。


    ASP.NET Forum
    Other Discussion Forums
    FreeRice Donate
    Issues to report
    Free Tech Books Search and Download

    2014年7月19日 8:16
    版主