2010-08-11 6 views
0

j'ai besoin d'aide avec cette procédure:Aide rollback procédure SQL Server

ce que son supposé faire est d'essayer d'insérer un nouvel utilisateur s'il n'y a pas d'autre avec le même nom.

S'il existe déjà un utilisateur, il doit annuler la validation. Mais ça ne marche pas, ça s'engage quand même.

Des suggestions?

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 
+0

Avez-vous évalué la réponse que j'ai donnée? Vous pouvez faire la tâche en une seule étape. – ErikE

Répondre

2

Je ne pense pas que @varCheckUser sera jamais NULL, s'il n'y a pas de ligne, il sera 0

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

vous risquez de rendre 0

également de vérifier comme celui-ci pour NULL

if (@varCheckUser IS NOT null) 

pourquoi ne pas vous faire quelque chose comme ça

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

puis vérifier qu'il n'y a pas 1

pourquoi avez-vous besoin de la tran? Il suffit de faire quelque chose comme ça

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 

probablement une bonne idée de faire usu_ds un primary key ou ajouter un unique constrain t, de cette façon que personne ne peut mettre à jour son nom d'utilisateur à quelque chose qui existe et personne ne peut en utiliser erreur SSMS et changer un utilisateur nom à quelque chose qui est déjà dans la table

+0

ce que "FI EXISIT" vérifie? Je ne savais pas ce stamement – ozsenegal

+0

@ ozsenegal: lire sur EXISTS dans la documentation en ligne de SQL Server: http://msdn.microsoft.com/en-us/library/ms188336.aspx –

+0

vérifie si une ligne existe – SQLMenace

0

@varCheckUser ne peut jamais être nul. Il aura toujours une valeur qui est une représentation sous forme de chaîne d'un entier.

Au lieu de:

if (@varCheckUser <> null) 

Do:

if (@varCheckUser = 0) 
1

Vous devez changer votre chèque à utiliser @varCheckUser = 0 - ou mieux encore, changer d'utiliser IF EXISTS et ne jamais commencer une transaction à insérer les valeurs si cet utilisateur n'existe pas déjà:

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 

Il ne sert à rien de lancer une transaction juste pour la renvoyer, si vous pouvez vérifier l'existence de l'utilisateur avant de le faire. Plus: si la colonne usu_ds doit être unique, vous devez également lui appliquer une contrainte UNIQUE! De cette façon, si vous obtenez des erreurs (violations de contrainte) si quelqu'un parvient à essayer d'insérer un utilisateur d'une autre manière (autrement que par votre proc stocké):

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

Si vous voulez écrire du code comme celui-ci, je pense que vous devriez au moins faire un effort pour gérer correctement la concurrence. Il n'y a vraiment aucun intérêt à vérifier l'existence de l'utilisateur à l'avance si vous ne prenez pas soin des conditions de course qui rendent inutile le contrôle de l'existence. – ErikE

0

@varCheckUser <> NULL retournera toujours FAUX .

Vous devez utiliser @varChechUser IS NOT NULL

1

Il ne doit pas si compliqué que ça.

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 

Ce code permet de résoudre complètement les problèmes d'accès concurrentiel pour vous aussi bien (voir Conditional Insert/Update Race Condition).