日期:2014-05-19  浏览次数:20451 次

重复读取数据
表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的代码,以重新创建测试环境.