数据库的并发处理之悲观锁与乐观锁

  概述

  1. 何为并发?并发是指两个或多个事件在同一时间间隔内发生。
  2. 程序去预防并发的基本思路就是讲并行执行改为串行执行,也就是拉队列。
  3. 数据库针对并发的处理一般采用悲观并发处理和乐观并发处理。
  4. 数据库悲观锁是一种串行运算,假定会发生并发冲突,屏蔽一些可能违法数据完整性的操作。悲观锁假定其他用户企图访问或者更改对象的效率是很高的,所以会在程序开始改变对象之前就将对象锁住,知道提交了所做的更改之后才释放所。缺点是不论是页锁还是航所,加锁时间可能会很长,这样可能会长时间锁定一个对象,限制其他对象访问,并发访问性不好。
  5. 数据库乐观锁是一种并行运算,只是在提交操作时检查是否违反数据完整性。乐观锁不能解决脏读问题。乐观锁假定不会发生并发冲突,因此知道程序准备提交所做的更改时才将对象锁住,当程序读取以及改变对象时并不加锁。乐观锁加锁时间要比悲观锁短,可以用于较大锁力度获得较好的并发访问性能。由于用户提交时,数据库对象可能已经发生了变化,这样用户不得不重新读取对象,增加了用户读取对象的次数。

  实践

    悲观者方法

    加了updlock锁,锁定了更新操作。

      

ALTER PROCEDURE [dbo].[beiguansuo]
AS
BEGIN
	declare @age int 
	begin tran
	select @age=age from Student with(updlock) where  FirstName='fengjie'
	waitfor delay '00:00:05'
	update [dbo].[Student] set Age=@age-1 where FirstName='fengjie'
	commit tran
END

  乐观者方法

  数据库列有一个类型为“timestamp”,是一个时间戳,可以理解为版本号。一旦有访问者修改了该数据,版本号的值就会发生改变。我们在更改数据之前首先获取该记录的版本号,然后在记录更新的时候通过主键和版本号同时去更新。但是这样会出现一个问题,如果我们拿到版本号后,数据已经被修改了,这时候update的影响行数为0。所以在这里程序需要根据返回行做特殊处理,可以提醒用户刷新后再修改,也可以递归去Update,根据具体的业务场景选择不同的方法。

  

ALTER PROCEDURE [dbo].[leguansuo]
AS
BEGIN
	declare @rowversion timestamp
	declare @age int
	
	select @rowversion=RowVersion,@age=Age from Student

	update Student set Age=@age-1 where FirstName='fengjie' and RowVersion=@rowversion
END

 

Main(){
var upRows = executeLeguansuo();
            int retry = 10;
            while (upRows==0&&retry>0)
            {
                Thread.Sleep(500);
                retry--;
                upRows = executeLeguansuo();
            }
}

private int executeLeguansuo() {
            string sql = "exec leguansuo";
            using (myEntities context = new myEntities())
            {
                int upRows = context.Database.ExecuteSqlCommand(sql, new object[] { });
                if (upRows==0)
                {
                    executeLeguansuo();
                }
                return upRows;
            }
        }

  EF框架如何避免数据库并发

    在EF DataBaseFirst中,只需要设置类型为TimeStamp版本号的并发模式属性即可。默认是None,设置为Fixed即可。

  在线系统发生并发时,程序会抛出异常,我们捕获这个异常然后结合业务场景选择不同的处理方式即可。

  

public class SaveChangesForBF : BingFaTestEntities
    {
        public override int SaveChanges()
        {
            try
            {
                return base.SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex)//(OptimisticConcurrencyException)
            {
                //并发保存错误
                return -1;
            }
        }
    }

  本文有内容引用自:http://www.cnblogs.com/chenwolong/p/BF.html

      

posted @ 2018-03-29 18:13  chenxizhaolu  阅读(469)  评论(0编辑  收藏  举报