程序中多用户并发一点总结

在多用户环境中,大家同时更新相同记录时可能会引发冲突,这一个问题用专业的术语描述叫做并发性。并发会造成什么样的冲突?并性主要会导致以下四种常见的问题。

代码
1、脏读取:当一个事物读取其它完成一半事务的记录时,就会发生脏读取。
   例:用户A和用户B看到的值都是5,用户B将值修改为2,用户A看到的值仍然是5,这时就发生了脏读取。
  
2、不可重复读取:在每次读数据时,如果你获得的值都不一样,那表明你遇到了不可重复读取问题。
    例:用户A看到的值是5,用户B将值修改为2,用户A刷新后看到的值仍然是5,这时就发生了不可重复读取。
  
3、虚幻行:如果update和delect SQL语句未对数据造成影响,很可能遇到了虚幻行问题。
    例:用户A将所有值都把5修改为2,用户B使用值2插入一个新记录,用户A查询所有值为2的记录,但却找不到新添加的记录,这时就叫虚幻行。
  
4、更新丢失:一个事务的更新覆盖了其它事务的更新结果,就是所谓的更新丢失。
    例:用户A将所有值从5修改为2,用户B将所有值从2修改为5,用户A丢失了他的更新。

 

  如何解决上述冲突?

  答案是使用乐观锁悲观锁。什么是乐观锁?顾名思义,乐观锁是假设多个事务相互不会影响对方,换句话说,就是在乐观锁模式下,没有锁操作会得到执行,事务只是验证是否有其它事务修改数据,如果有则进行事务回滚,否则就提交。

  乐观锁的工作原理:

    a、记录当前的时间戳,

    b、开始修改值

    c、在更新前,检查是否有其他人更新了值(通过检查新旧时间戳实现)

    d、如果不相等就回滚,否则就提交

  在这里,我将使用三个方法处理乐观锁,包括ADO.Net数据集(Dataset)、SQL时间戳数据类型和新旧值检查。下面谈谈利用这三种方法实现乐观锁。

  实现乐观锁的解决方案
  在.NET中,实现乐观锁的方法主要有三种:
    1、数据集(Dataset):数据集是实现乐观锁的默认方法,在更新前它会检查新旧值。
    2、时间戳数据类型(timestamp):在你的表中创建一个timestamp数据类型,在更新时,检查旧时间戳是否等于新时间戳。
    3、直接检查新旧值:在更新时检查旧值和新值是否相等,如果不相等就回滚,否则就提交。

代码
解决方案1:使用timestamp数据类型
  SQL Server有一个数据类型是timestamp,它是实现乐观锁的另一种途径,每次更新SQL Server数据时,时间戳会自动产生一个唯一的二进制数值,时间戳数据类型可用来版本化你的记录更新。
  为了实现乐观锁,首先需要取得旧的时间戳值,在更新时检查旧的时间戳值是否等于当前时间戳,然后检查是否发生了更新操作,如果没有发生更新,则使用SQL Server的raiserror产生一系列错误消息。如果发生了并发冲突,当你如下图所示这样调用ExecuteNonQuery时,你应该会看到错误传播。
解决方案2:检查旧值和新值
  许多时候,我们只需要检查相关字段值的一致性,其它字段则可以忽略,在update语句中,我们可以直接做这种比较。