读书人

关于编号事宜这么用可否

发布时间: 2013-12-26 00:35:35 作者: rapoo

关于编号,事务这么用可否

CREATE TABLE [dbo].[test](
[id] [varchar](15) NULL
) ON [PRIMARY]

GO


Create procedure [dbo].[getIDonly]
(
@name varchar(2),
@re varchar (50) output
)
AS
BEGIN
begin TRANSACTION
declare @GD varchar(15) --固定左边
set @GD= (select @name+ cast (YEAR (getdate()) as varchar(4))+cast (MONTH (GETDATE ()) as varchar(2))+CAST (day(GETDATE()) as varchar(2)))
declare @DT varchar(5) ---动态右边
set @DT=(select right (left( max(CAST ( RIGHT (id,5) as NUMERIC(20,0))*100001+1),10),5) from test where id like @name +'%' )


if @DT is null
begin
set @DT='00001'
end

if @@error<>0
begin
rollback tran
end
commit tran
set @re= @GD+@DT
END




[解决办法]
在高并发环境下,最好不要使用MAX这类方法
[解决办法]
参考一下我的文章http://blog.csdn.net/dba_huangzj/article/details/7685162
[解决办法]
把最大的编号存放到指定表中,然后每次都从这个表中去取数。

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go


ALTER PROCEDURE [dbo].[SOF_getmaxbh]
@biaoshi varchar(3), --单据类型标识
@addflag integer, --0,1 在前台使用;2 组成一个号返回,序号不加1(结转号),3 序号加 1 返回(单据编号);
@maxbh varchar(11)=NULL output --直接返回编号
AS


--内部变量声明
declare @recnum integer,
@rowcount integer
set @recnum=0

/*非事务内容执行*/
--每一过程拥有一唯一区界号,过程内的异常编号在此基础上增加
declare @errcode integer
set @errcode=1800
declare @return integer
set @return=0

--启动事务处理
declare @tran_point int--控制事务嵌套
set @tran_point=@@trancount--保存事务点

if @tran_point=0
begin tran tran_SOF_getmaxbh
else
save tran tran_SOF_getmaxbh

if @addflag=1 or @addflag=3
begin

update maxbh set @recnum=recnum=isnull(recnum,0)+1 where biaoshi=@biaoshi
set @rowcount=@@rowcount
if @@error<>0
begin
set @return=1
goto err_lab
end
end
else
begin

select @recnum=isnull(recnum,0) from maxbh(nolock) where biaoshi=@biaoshi
end

if @rowcount=0
begin
set @recnum=0
insert into maxbh (biaoshi,maxbh,mkbh,recnum) values (@biaoshi,'','',@recnum)
end

--返回结果
declare @s_recnum varchar(11)
set @s_recnum=LTRIM(str(@recnum))

if @addflag>1
set @maxbh=@biaoshi+ REPLICATE('0',11-len(@biaoshi)-len(@s_recnum))+@s_recnum
else
select @biaoshi+ REPLICATE('0',11-len(@biaoshi)-len(@s_recnum))+@s_recnum as recnum

--结束事务处理
if @tran_point=0
commit tran tran_SOF_getmaxbh
goto return_lab

err_lab:
if @return<100 set @return=@errcode +@return
rollback tran tran_SOF_getmaxbh

return_lab:
return @return

[解决办法]
引用:
还有我生成编号的代码,是否有更优的方式来写


可以适当简化成这样:
Create procedure  [dbo].[getIDonly]
(
@name varchar(2),
@re varchar (50) output


)
AS
BEGIN
begin TRANSACTION
declare @GD varchar(15) --固定左边
set @GD= @name+ convert(varchar(8),GETDATE(),112)

declare @DT varchar(5) ---动态右边
set @DT=(select right (left( max(CAST ( RIGHT (id,5) as NUMERIC(20,0))*100001+1),10),5) from test where id like @name +'%' )


if @DT is null
begin
set @DT='00001'
end

if @@error<>0
begin
rollback tran
end
commit tran
set @re= @GD+@DT
END


[解决办法]
另外,在高并发的情况下,如果你使用max,确实有可能会取到重复的id的。

比如,用户A,用户B都执行了你的存储过程,然后都求max,然后得到了同一个值,那么这个时候,在进行其他的操作的时候,就有可能因为主键重复,而拨错
[解决办法]
除了并发,如果表越来越大,MAX的时间就越来越长,这时候多会话操作的话,得到的数据可能并不是你想要的
[解决办法]
会,因为你要取MAX(BH),虽然加了with,不过会导致阻塞甚至死锁
[解决办法]
那个select ... output ...应该比较好

读书人网 >SQL Server

热点推荐