первая попытка оперативной транзакции - PullRequest
1 голос
/ 18 февраля 2011

Я пытаюсь написать sproc с транзакцией.Кто-нибудь может сказать мне, будут ли какие-либо проблемы с кодом ниже или он будет работать как задумано?

ALTER procedure [dbo].[DeleteMetricMeter]

(
    @SectionID int,
    @MetricMeterID int,
    @Result bit output
)

as

declare @MetricMeterCount int
declare @err int
declare @rowcount int

set xact_abort on

begin tran

select @MetricMeterCount = count(*) from luMetricMeters
where fkSectionID = @SectionID

select @err = @@error, @rowcount = @@rowcount 

if (@err <> 0) or (@rowcount = 0)
begin
    goto on_error           
end

delete from luMetricMeterList
where pkMetricMeterID = @MetricMeterID

select @err = @@error, @rowcount = @@rowcount 

if (@err <> 0) or (@rowcount = 0)
begin
    goto on_error           
end 

delete from luMetricMeters
where pkMetricMeterID = @MetricMeterID

select @err = @@error, @rowcount = @@rowcount 

if (@err <> 0) or (@rowcount = 0)
begin
    goto on_error           
end

if (@MetricMeterCount = 1)
begin
    delete from luMetricSections
    where pkSectionID = @SectionID

    select @err = @@error, @rowcount = @@rowcount 

    if (@err <> 0) or (@rowcount = 0)
    begin
        goto on_error           
    end
end

commit tran
set @result = 1
return @result

on_error:
    rollback tran
    set @result = 0
    return @result

Ответы [ 2 ]

1 голос
/ 18 февраля 2011

Если вы используете Sql Server 2005+, я бы рекомендовал использовать TRY ... CATCH (Transact-SQL) и взглянуть на раздел [ B. Использование TRY… CATCH в транзакции ]

Это ОТЛИЧНО упростит вашу процедуру.

0 голосов
/ 18 февраля 2011

Есть несколько проблем с процедурой:

  • Вы не должны оценивать количество строк, если это действительно не указывает на ошибку. Если данные не удалены, откат не требуется.
  • Ваш код не является потокобезопасным. Запрос MetricMeterCount должен быть изменен на этот, чтобы другие потоки не выполняли удаление между вашим выбором и выполнением удаления:

    select @MetricMeterCount = count(*) 
      from luMetricMeters with (xlock, serializable)
     where fkSectionID = @SectionID  
    

Я бы написал такой код:

ALTER procedure [dbo].[DeleteMetricMeter]

(
    @SectionID int,
    @MetricMeterID int,
    @Result bit output
)

as

DECLARE @MetricMeterCount int
DECLARE @err int
DECLARE @rowcount int

SET xact_abort ON

BEGIN TRAN

DELETE FROM luMetricMeterList 
 WHERE pkMetricMeterID = @MetricMeterID

SELECT @err = @@error

IF (@err <> 0) 
    GOTO on_error           

DELETE FROM luMetricMeters
 WHERE pkMetricMeterID = @MetricMeterID

SELECT @err = @@error

IF (@err <> 0) 
    GOTO on_error           

IF EXISTS (SELECT * 
             FROM luMetricMeters WITH (xlock, serializable) 
            WHERE fkSectionID = @SectionID)
BEGIN
    DELETE FROM luMetricSections 
     WHERE pkSectionID = @SectionID

    SELECT @err = @@error
    IF (@err <> 0) 
        GOTO on_error           
END

COMMIT TRAN

RETURN (0)

on_error:
    ROLLBACK TRAN
    RETURN (-1)
GO

Примечание: возвращаемые значения должны быть 0 для успеха и отрицательное число для неудачи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...