一个表(表名 TestTable)有三个字段,其中
ID 自增列
Name 唯一键 nvarchar
Code 唯一键 nvarchar
一般我这样写存储过程
create proc create
(
@Name nvarchar(50),
@Code nvarchar(50)
)
as
begin
if exists(select 1 from TestTable where Name=@Name)
return -1; if exists(select 1 from TestTable where Code=@Code)
return -2;
set @status int;
begin try
insert into TestTable(Name,Code) select @Name,@Code;
set @status=@@ROWCOUNT;
end try
begin catch
set @status=-255;
end catch
return @status;
end现在我的问题是,会不会,即使前面两条if语句已经做了判断,当执行到insert语句前,别的客户端程序已经调用了这个过程并提供了一个相同的@Name,所以在执行insert语句时发生异常,然后进入到begin catch中?
我是不是应该修改insert语句像下面这样:
insert into TestTable(Name,Code) select @Name,@Code where
(not exists(select 1 from TestTable where Name=@Name))
and
(not exists(select 1 from TestTable where Code=@Code))感谢不尽
ID 自增列
Name 唯一键 nvarchar
Code 唯一键 nvarchar
一般我这样写存储过程
create proc create
(
@Name nvarchar(50),
@Code nvarchar(50)
)
as
begin
if exists(select 1 from TestTable where Name=@Name)
return -1; if exists(select 1 from TestTable where Code=@Code)
return -2;
set @status int;
begin try
insert into TestTable(Name,Code) select @Name,@Code;
set @status=@@ROWCOUNT;
end try
begin catch
set @status=-255;
end catch
return @status;
end现在我的问题是,会不会,即使前面两条if语句已经做了判断,当执行到insert语句前,别的客户端程序已经调用了这个过程并提供了一个相同的@Name,所以在执行insert语句时发生异常,然后进入到begin catch中?
我是不是应该修改insert语句像下面这样:
insert into TestTable(Name,Code) select @Name,@Code where
(not exists(select 1 from TestTable where Name=@Name))
and
(not exists(select 1 from TestTable where Code=@Code))感谢不尽
参考 https://technet.microsoft.com/zh-cn/ms189749
有加约束,但是这样会进行到catch中,依赖引发异常不是一个好的办法,我个人认为
有加约束,但是这样会进行到catch中,依赖引发异常不是一个好的办法,我个人认为就现在的代码来看,也没有什么大问题,你说的问题的出现概率小于万分之一的。
如果要100%避免这个问题,最有效和简单的方法就是在前台调用的时候,限制进程的新建,在前一个进程结束前,不允许执行create存储过程。
更正一下,上面的做法,应该是同时在存储过程和 CLR 里面修改才生效。如果要完全写在存储过程里面,可能还要使用 holdlock 表提示符和 begin transaction 语句。
更正一下,上面的做法,应该是同时在存储过程和 CLR 里面修改才生效。如果要完全写在存储过程里面,可能还要使用 holdlock 表提示符和 begin transaction 语句。
感谢您的回复。系统确定只有那么几个人在使用,我也清楚出现这种情况的概率极低,我是希望可以用正确的方法做正确的事情,不考虑并发量的问题。。像我上面这样写会不会有问题:insert into TestTable(Name,Code) select @Name,@Code where
(not exists(select 1 from TestTable where Name=@Name))
and
(not exists(select 1 from TestTable where Code=@Code))
更正一下,上面的做法,应该是同时在存储过程和 CLR 里面修改才生效。如果要完全写在存储过程里面,可能还要使用 holdlock 表提示符和 begin transaction 语句。
感谢您的回复。系统确定只有那么几个人在使用,我也清楚出现这种情况的概率极低,我是希望可以用正确的方法做正确的事情,不考虑并发量的问题。。像我上面这样写会不会有问题:insert into TestTable(Name,Code) select @Name,@Code where
(not exists(select 1 from TestTable where Name=@Name))
and
(not exists(select 1 from TestTable where Code=@Code))
同样有问题,exists 子查询的锁范围是不够的。只有锁定表才能完全阻止重复。
在你成功插入数据后
select @count_name=count(name) from 表 where name=@name
select @count_code=count(code) from 表 where code=@code
if @count_name >1 or @count_code >1
回滚
...