明凯博客

关注网站技术,一个特立独行的程序员

乐观并发检查失败的解决方法

解释:
ADO操纵SQL的锁定机制:

锁定一般分为“乐观锁定”和“悲观锁定”。
也叫:“保守式记录锁定”和“开放式记录锁定”

在ADO中,锁定行为作用于一条记录,即:行锁。这种锁定提高了并发粒度。
(即可以有多个并发对同一个对像进行操作,而表级锁定,当一个并发锁定表后,其他并发都不能更新此表,直到锁定完成。
而行锁不同,它只锁定行中的一行,当一个并发锁定表中一行时,其他并发还可以更新其它行)。

同时,行锁增加了SQL SERVER的系统开锁。

SQL自动管理锁,并使用合适的锁定粒度:
Microsoft SQL Server 使用动态锁定策略确定最经济的锁。
应用程序开发人员可以集中精力进行开发。SQL Server 自动调整锁定。

设有两个连接:A、B

乐观锁定:
A在执行UPDATE这一刻才锁定数据,锁定后的数据,在执行锁定当时那一刻之前是可以被B更改的,但被B更改后,A在UPDATE时会收到一错误消息:“乐观并发检查失败。已在此游标之外修改了该行。”

还有一种情况,当大量并发连接更改数据时,可能在你锁定这一刻的同时有连接B也同时UPDATE,此时会发生“阻塞”。也就是A连接完成UPDATE前,B连接一直处理等待状态。

当然,乐观锁定发生“阻塞”的可能性很小,因为锁定只发生在UPDATE那一刻,但不代表不发生。
乐观并发:乐观并发控制假定不太可能(但不是不可能)在多个用户间发生资源冲突。

乐观锁定的这种特性,造成了一个缺点:使用乐观锁定时,不能确保在UPDATE时能成功。

悲观锁定:
A在执行数据修改时,UPDATE之前就对数据进行锁定,比如:objRs2(“iOrder_Qty”) = Rnd 这条语句执行时,数据就会被锁定。

此时,B如果使用的乐观锁定,那么在B执行UPDATE时,会发生阻塞,阻塞直到A完成UPDATE并对数据解锁;此时B才能继续。
当然B出错,因为B打开记录时为x,而A执行UPDATE后变成了y,所以B会报错:“乐观并发检查失败。已在此游标之外修改了该行。”
还有一种可能是B因为等待太久超时而返回错误:“[DBNETLIB][ConnectionRead (WrapperRead()).]一般性网络错误。请检查网络文档。”

另外:B如果使用的悲观锁定,那么在B执行数据修改时,UPDATE之前就会阻塞,比如:objRs2(“iOrder_Qty”) = Rnd 这条语句执行时,阻塞发生。

A被称为“阻塞者”,B是“被阻塞者”,在SQL企业管理器中:A为“正在阻塞”,B会列出阻塞者的spid,即是A。

综上:在一般企业应用程序设计时,使用“乐观锁定”以便得到高并发性。而对阻塞的处理,使用超时错误处理机制。
实际上使用ADO+SQL不太需要考虑锁的问题,因为这都由SQL SERVER为你代劳了。

只有一种情况要避免:在程序中因为执行顺序而引起阻塞,此时的阻塞无法解除,形同“死锁”。只能在“企业管理器”中取消阻塞者的进程。或者等待超时。

在SQL企业管理器中查看阻塞的路径为:Microsoft SQL Servers/SQL Server组/Server Name/管理/当前活动/ [锁/进程 ID]

解决方法:

修改记录时,用1,2打开。

1
2
3
4
5
6
7
8
9
10
RS.OPEN SQL,CONN,A,B 
A: ADOPENFORWARDONLY(=0) '只读,且当前数据记录只能向下移动 
ADOPENSTATIC(=3) '只读,前数据记录可自由移动 
ADOPENKEYSET(=1) '可读写,当前数据记录可自由移动 
ADOPENDYNAMIC(=2) '可读写,当前数据记录可自由移动,可看到新增记录 
 
B: ADLOCKREADONLY(=1) '默认值,用来打开只读记录 
ADLOCKPESSIMISTIC(=2) '悲观锁定 
ADLOCKOPTIMISTIC(=3) '乐观锁定 
ADLOCKBATCHOPTIMISTIC(=4) '批次乐观锁定

因为同一时刻可能有N多个人请求数据的修改操作,所以可能这时候就会有冲突吧。按照上面的修改就会解决上诉问题。

, , , ,

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注