Помогите с откатом процедуры SQL Server - PullRequest
0 голосов
/ 12 августа 2010

Мне нужна помощь с этой процедурой:

То, что он должен сделать, это попытаться вставить нового пользователя, если нет другого пользователя с таким же ИМЯ.

Если пользователь уже существует, он должен выполнить откат, иначе зафиксировать. Но это не работает, оно все равно фиксируется.

Есть предложения?

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 ]

2 голосов
/ 12 августа 2010

Я не думаю, что @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

зачем вам тран?Просто сделайте что-то вроде этого

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 голос
/ 12 августа 2010

Это не так уж сложно.

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

Этот код также полностью решает любые проблемы параллелизма (см. Условное условие вставки / обновления гонки ).

1 голос
/ 12 августа 2010

Вам нужно изменить свой чек на использование @varCheckUser = 0 - или еще лучше, измените его на использование IF EXISTS и только когда-либо начните транзакцию для вставки значений, если этого пользователя еще не существует:

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 должен быть уникальным, на него также следует наложить УНИКАЛЬНОЕ ограничение! Таким образом, если вы получите ошибки (нарушения ограничений), если кому-то удастся попытаться вставить пользователя другим способом (кроме как через ваш сохраненный процесс):

ALTER TABLE dbo.Usuarios
  ADD CONSTRAINT UX_usu_ds UNIQUE(usu_ds)
0 голосов
/ 12 августа 2010

@ varCheckUser <> NULL всегда возвращает FALSE.

Вы должны использовать @varChechUser IS NOT NULL

0 голосов
/ 12 августа 2010

@ varCheckUser никогда не может быть нулевым.Он всегда будет иметь строковое представление целого числа.

Вместо:

if (@varCheckUser <> null)

Do:

if (@varCheckUser = 0)
...