帮助SQL Server过程回滚

时间:2010-08-11 20:45:33

标签: sql-server tsql insert exists

我需要一些帮助来完成这个程序:

如果没有其他人使用相同的NAME,它应该尝试插入一个新用户。

如果已有用户,则应该回滚其他提交。但它不起作用,无论如何都会提交。

有什么建议吗?

SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO

ALTER procedure [dbo].[SP_USUARIOS_INSERT]
@usu_ds varchar(50),
@usu_dt_create datetime,
@usu_dt_lst_log datetime,
@usu_ds_senha varchar(255),
@usu_ds_email varchar(100)
as
begin
declare @varCheckUser varchar(100) = null;
set @varCheckUser = (select COUNT(usu.usu_Ds) from Usuarios usu where usu.usu_ds = @usu_ds);
begin transaction
insert into Usuarios(usu_ds,usu_dt_create,usu_dt_lst_log,usu_ds_senha,usu_ds_email) values(@usu_ds,@usu_dt_create,@usu_dt_lst_log,@usu_ds_senha,@usu_ds_email)
if (@varCheckUser <> null)
begin
 RAISERROR('User already exists',16,1)
 rollback transaction
 return
end
else
begin
commit transaction
end
end

5 个答案:

答案 0 :(得分:2)

我认为@varCheckUser永远不会为NULL,如果没有行则为0

set @varCheckUser = (select COUNT(usu.usu_Ds) 
from Usuarios usu where usu.usu_ds = @usu_ds);

这将使其成为0

你也可以这样检查NULL

if (@varCheckUser IS NOT null)

你为什么不做这样的事呢

IF  EXISTS (select 1 
               from Usuarios usu 
                where usu.usu_ds = @usu_ds)
SET @varCheckUser =1

然后检查它不是1

为什么你需要tran?做这样的事情

IF  EXISTS (select 1 
                   from Usuarios usu 
                    where usu.usu_ds = @usu_ds)
BEGIN
RAISERROR('User already exists',16,1)
RETURN
END
ELSE
BEGIN
insert into Usuarios(usu_ds,usu_dt_create,usu_dt_lst_log,usu_ds_senha,usu_ds_email)
values(@usu_ds,@usu_dt_create,@usu_dt_lst_log,@usu_ds_senha,@usu_ds_email)

END

将usu_ds设为primary key或添加unique constrain t可能是个好主意,这样任何人都无法将用户名更新为存在的内容,没有人可以错误地使用SSMS并更改用户名到表格中已有的东西

答案 1 :(得分:1)

您需要更改支票以使用@varCheckUser = 0 - 或者更好的是,将其更改为使用IF EXISTS,并且只有在该用户尚不存在时才开始插入值的事务:< / p>

IF NOT EXISTS(SELECT * FROM dbo.Usuarios usu WHERE usu.usu_ds = @usu_ds)
BEGIN
   BEGIN TRANSACTION

   INSERT INTO 
      dbo.Usuarios(usu_ds, usu_dt_create, usu_dt_lst_log, usu_ds_senha, usu_ds_email)     
   VALUES(@usu_ds, @usu_dt_create, @usu_dt_lst_log, @usu_ds_senha, @usu_ds_email)

   COMMIT TRANSACTION
END

如果您可以事先检查用户是否存在,那么开始交易只是为了回滚它是没有意义的。

另外:如果列usu_ds应该是唯一的,那么你也应该对它设置一个UNIQUE约束!这样,如果有人设法尝试以其他方式插入用户(除了通过存储的proc),你就会收到错误(违反约束):

ALTER TABLE dbo.Usuarios
  ADD CONSTRAINT UX_usu_ds UNIQUE(usu_ds)

答案 2 :(得分:1)

没有那么复杂。

ALTER procedure [dbo].[SP_USUARIOS_INSERT]
   @usu_ds varchar(50),
   @usu_dt_create datetime,
   @usu_dt_lst_log datetime,
   @usu_ds_senha varchar(255),
   @usu_ds_email varchar(100)
AS

SET NOCOUNT, XACT_ABORT ON 
INSERT Usuarios(usu_ds, usu_dt_create, usu_dt_lst_log, usu_ds_senha, usu_ds_email) 
SELECT @usu_ds, @usu_dt_create, @usu_dt_lst_log, @usu_ds_senha, @usu_ds_email
WHERE
   NOT EXISTS (
      SELECT 1
      FROM Usuarios WITH (UPDLOCK, HOLDLOCK)
      WHERE usu_ds = @usu_ds
   )
IF @@RowCount = 0 BEGIN
   RAISERROR('User already exists', 16, 1)
   RETURN
END

此代码也完全解决了您的任何并发问题(请参阅Conditional Insert/Update Race Condition)。

答案 3 :(得分:0)

@varCheckUser永远不能为空。它将始终具有一个整数的字符串表示形式的值。

而不是:

if (@varCheckUser <> null)

执行:

if (@varCheckUser = 0)

答案 4 :(得分:0)

@varCheckUser&lt;&gt; NULL将始终返回FALSE。

您必须使用@varChechUser IS NOT NULL