日期:2014-05-18  浏览次数:20610 次

为什么这个存储过程的事务未起作用
在项目中用到一个生成订单流水号的存储过程,有可能在项目不同的地方调用这个存储过程,本来希望每次调用存储过程都获取到不重复的单号,因该存储过程已用事务控制,程序开始时用begin tran,最后结束时才commit tran,中间如果发生错误就rollback tran并且return。但却发现这个事务好象没起作用,有时候两个不同的地方调用这个存储过程会取到相同的单号。后来分析了一下,可能是update sys_id set new_id=@sysid where bill_type=@billtype这行执行时未成功,后面回滚事务抛出异常的语句没起作用,这样就造成调用该存储过程得到了最新的单号,而存储当前流水号的sys_id这个表的单号却没有同步更新。导致下一次调用该存储过程又会取到刚才已经取到的单号。下面将存储过程的代码贴出来,请高手帮忙看一下这个存储过程为什么事务控制没起作用。谢谢!

CREATE PROC [dbo].[proc_getsysid]
@bill_name varchar(20) , 
@sysid varchar(32) output
as
declare @newid varchar(32)
declare @idhead varchar(32)
declare @datetype varchar(32)
declare @billtype varchar(32)
declare @idnum int
declare @idcount int
declare @numcount int

begin tran  

select @billtype=bill_type,@newid=new_id,@idhead=id_head,@datetype=date_type,@numcount=num_count from sys_id where bill_type=@bill_name
if(@billtype is null)
begin
rollback tran
raiserror 50105 'WRONG BILL TYPE!'
return -1
end

set @sysid=''
if(upper(@idhead)!='NONE')
begin
set @sysid=upper(@idhead)
end
if(upper(@datetype)='YYYYMMDD')
begin
set @sysid=@sysid+substring(convert(varchar,getdate(),112),1,8)
end
else if(upper(@datetype)='YYMMDD')
begin
set @sysid=@sysid+substring(convert(varchar,getdate(),112),3,6)
end
else if(upper(@datetype)='YYYYMM')
begin
set @sysid=@sysid+substring(convert(varchar,getdate(),112),1,6)
end
else if(upper(@datetype)='YYMM')
begin
set @sysid=@sysid+substring(convert(varchar,getdate(),112),3,4)

end
else if(upper(@datetype)='YYYY')
begin
set @sysid=@sysid+substring(convert(varchar,getdate(),112),1,4)
end
else if(upper(@datetype)='YY')
begin
set @sysid=@sysid+substring(convert(varchar,getdate(),112),3,2)
end


if(@newid is null)
begin
set @idcount=1
while(@idcount<@numcount)
begin
set @sysid=@sysid+'0'
set @idcount=@idcount+1
end

set @sysid=@sysid+'1'
end
else if(@sysid=substring(upper(@newid),1,len(@sysid))and len(@sysid)>0 )
begin
set @idnum=convert(int,substring(@newid,len(@sysid)+1,@numcount))+1
if(len(@idnum)>@numcount)
begin
raiserror 50105 'OUT OF NUMBER!'
return -1
end
set @idcount=len(@idnum)
while(@numcount-@idcount>0)
begin
set @sysid=@sysid+'0'
set @idcount=@idcount+1

end
set @sysid=@sysid+convert(varchar,@idnum)

end
else if(len(@sysid)=0 and len(@newid)=@numcount )
begin
set @idnum=convert(int,substring(@newid,len(@sysid)+1,@numcount))+1
if(len(@idnum)>@numcount)
begin
raiserror 50105 'OUT OF NUMBER!'
return -1
end
set @idcount=len(@idnum)
while(@numcount-@idcount>0)
begin
set @sysid=@sysid+'0'
set @idcount=@idcount+1

end
set @sysid=@sysid+convert(varchar,@idnum)

end
else
begin
set @idcount=1
while(@idcount<@numcount)
begin
set @sysid=@sysid+'0'
set @idcount=@idcount+1
end

set @sysid=@sysid+'1'
end

if @@error <> 0  
begin
rollback tran
raiserror 50105 'GENERATE ERROR!'
return
end

update sys_id set new_id=@sysid where bill_type=@billtype

if @@error <> 0  
begin
rollback tran
raiserror 50105 'GENERATE ERROR!'
return
end  
   
commit tran

GO

------解决方案--------------------
加了事务,你语句读完就释放了,别的继续读当然读到与刚才一样的,加锁一直接保持(HOLDLOCK)