|
本文介绍了处理.NET中锁的6种方法,首先我们讨论一下并发性问题,然后讨论处理乐观锁的3种方法,乐观锁不能从根源上解决并发问题,因此后面我们介绍了悲观锁,最后介绍隔离级别如何帮助我们实现悲观锁,每个隔离级别都列举了示例进行说明,使得概念更加清晰。
我们为什么需要锁?
在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这就会产生冲突,这个就是著名的并发性问题。
图 1 并行性问题漫画
如何解决并发性问题?
借助正确的锁定策略可以解决并发性问题,资源被锁定后,其它进程想要访问它就会被阻止。
并发会造成什么样的冲突?
并发主要会导致四种常见的问题,详细情况请看下表。
问题 | 简要描述 | 解释 |
脏读取 | 当一个事务读取其它完成一半事务的记录时,就会发生脏读取 |
|
不可重复读取 | 在每次读数据时,如果你获得的值都不一样,那表明你遇到了不可重复读取问题 |
|
虚幻行 | 如果update和delete SQL语句未对数据造成影响,很可能遇到了虚幻行问题 |
|
更新丢失 | 一个事务的更新覆盖了其它事务的更新结果,就是所谓的更新丢失 |
|
如何解决上述冲突?
答案是使用乐观锁或悲观锁,下面将进一步进行阐述。
图 2 乐观锁和悲观锁
什么是乐观锁?
顾名思义,乐观锁假设多个事务相互不会影响对方,换句话说就是,在乐观锁模式下,没有锁操作会得到执行,事务只是验证是否有其它事务修改数据,如果有则进行事务回滚,否则就提交。
图 3 乐观锁
乐观锁是如何工作的?
实现乐观锁的方法有多种,但基本原则都一样,总是少不了下面五个步骤:
•记录当前的时间戳
•开始修改值
•在更新前,检查是否有其他人更新了值(通过检查新旧时间戳实现)
• 如果不相等就回滚,否则就提交
图 4 乐观锁的工作原理
实现乐观锁的解决方案
在.NET中,实现乐观锁的方法主要有三种:
•数据集(Dataset):数据集是实现乐观锁的默认方法,在更新前它会检查新旧值。
• 时间戳数据类型(timestamp):在你的表中创建一个timestamp数据类型,在更新时,检查旧时间戳是否等于新时间戳。
•直接检查新旧值:在更新时检查旧值和新值是否相等,如果不相等就回滚,否则就提交。
解决方案1:数据集
正如前面所说的,数据集是处理乐观锁的默认方法,下面是一个简单的快照,在Adapter的update函数上有一个调试点,当我移除断点运行update函数时,它抛出如下图所示的并行异常错误。
图 5 Update函数执行时抛出的异常错误
如果你运行后端分析器,你将会看到更新语句检查当前值和旧值是否相等:
exec sp_executesql N'UPDATE [tbl_items] SET [AuthorName] = @p1
WHERE (([Id] = @p2) AND ((@p3 = 1 AND [ItemName] IS NULL)
OR ([ItemName] = @p4)) AND ((@p5 = 1 AND [Type] IS NULL)
OR ([Type] = @p6)) AND ((@p7 = 1 AND [AuthorName] IS NULL)
OR ([AuthorName] = @p8)) AND ((@p9 = 1 AND [Vendor] IS NULL)
OR ([Vendor] = @p10)))',N'@p1 nvarchar(11),@p2 int,@p3
int,@p4 nvarchar(4),@p5 int,@p6 int,@p7
int,@p8 nvarchar(18),@p9 int,@p10 nvarchar(2)',
@p1=N'this is new',@p2=2,@p3=0,@p4=N'1001',@p5=0,@p6=3,@p7=0,
@p8=N'This is Old
Author',@p9=0,@p10=N'kk'
NET技术:.NET中锁6大处理方法 悲观乐观自己掌握,转载需保留来源!
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。