重复读取数据
表a
create table testa(
sno int,
cod varchar(6),
typ char(1))
我有两个程序调用一个存储过程proa,希望是一个过程调用选出的记录另一个程序不会选中他,写了下面的过程不知道对不。请大家给看看
create proa
as
declare @SNO int
begin tran
set @SNO=(select top 1 SNO from testa with (tablock) where typ= '0 ')
if @SNO is not null
begin
update testa set typ= '1 'where sno=@SNO
end
if @@error <> 0
goto errorhandle
commit tran
if @SNO is null
begin
select -1 as App_Error
return
end
select 0 as App_Error,SNO, cod
from testa
where SNO=@SNO
return
errorhandle:
if @@trancount> 0
rollback tran
select -1 as App_Error
return
go
------解决方案--------------------tablock不能禁止用户读相同的行,如果要禁止用户读取相同的行,要使用xlock锁.当一个用户使用xlock锁锁定了一行后,其他用户就必须等待xlock被解除后才能访问,而tablock锁不行.以下是在查询分析器中的测试:
连接一:创建测试使用的表
if object_id( 'tbTest ') is not null
drop table tbTest
GO
create table tbTest(id int,name varchar(10))
insert into tbTest
select 1, 'a ' union all
select 2, 'b '
GO
连接2:模拟第一个用户使用xlock锁锁定某行的情况,在锁定之后延时等待10秒,以测试其他用户是否能在xlock锁定期间读取到相同的行.请在连接2执行后立即执行连接3.
begin transaction
declare @name varchar(10)
select @name = name from tbTest with(xlock) where id = 1
waitfor delay '00:00:10 ' /*读出后等待10秒,以测试其它连接是否能读出同样的name*/
if @name = 'a '
update tbTest set name = '连接2 ' where id = 1
commit
GO
----查看
select * from tbTest
连接3:
begin transaction
declare @name varchar(10)
select @name = name from tbTest with(xlock) where id = 1
if @name = 'a '
update tbTest set name = '连接3 ' where id = 1
commit
GO
----查看
select * from tbTest
/*
连接2的测试结果为:
id name
----------- ----------
1 连接2
2 b
连接3的测试结果为:
id name
----------- ----------
1 连接2 /*更新不成功,读取的时候name已经不是 'a '了*/
2 b
*/
----清除测试环境
drop table tbTest
上面的测试结果说明连接2使用xlock锁之后,连接3用户无法读取到相同的行.每次重复测试时,请运行连接1的代码,以重新创建测试环境.