2009-03-06 3 views
14

Мы можем обернуть вызов хранимой процедуры в транзакции и указать уровень изоляции.Должны ли быть указаны транзакции вне хранимой процедуры или внутри?

Или мы можем поместить транзакцию внутри хранимой процедуры, указав там уровень изоляции.

Что лучше делать?

ответ

2

Это зависит от бизнес-логики, если SP является атомарным, он должен реализовать свою собственную транзакцию. Если вы этого не сделаете, вы рискуете ошибочным кодом в будущем, не создавая транзакцию переноса. поэтому, отвечая на ваш вопрос, я думаю, что транзакция должна идти внутри SP.

Конечно, вам нечего прекратить делать, атомарные SP реализуют свои собственные транзакции, и за пределами этой сферы могут существовать другие более широкие транзакции.

В целом при создании транзакций внутри SP вы уже можете быть в пределах транзакции, вам нужно закодировать этот экземпляр при выполнении Commit/Rollback.

+1

Не будет ли транзакция внутри SP просто соединяться с внешней областью транзакций, чтобы фиксация/откат работали прозрачно? –

6

Необходимо применять последовательный подход. Имейте в виду, что откат транзакции в хранимой процедуре откатывает любую область транзакций вложенности, включая любую внешнюю область.

Я бы посоветовал вам хранить ваши транзакции вне процедур. Таким образом, вы сохраняете полный контроль.

+0

это неверно. Если вы вставляете несколько начальных запусков BEGIN TRANSACTION и самый глубокий из них откатывается назад, все они откатываются назад ... – MatBailie

+0

@ Dems: Вы отчасти правы в том, что это только в случае, если вы не используете транзакцию с параметром transaction_name. Вот почему транзакции должны быть явно определены для полного контроля. См. Http://msdn.microsoft.com/en-us/library/ms189336.aspx для справки. –

+0

Демс: почему-то я написал «принять» вместо «откат», что не имело никакого смысла. Спасибо за то, что указали :-) –

6

Внутри хранимой процедуры наиболее подходящее место, на мой взгляд.

Одним из основополагающих правил хорошей конструкции транзакций является максимально короткий срок службы транзакции, поэтому фиксация должна произойти сразу после завершения логики транзакции. Управление транзакцией за пределами хранимой процедуры приведет к неоправданному продлению срока действия транзакции.

Вы также должны учитывать, что определение транзакции в рамках процедуры также обеспечит большую четкость вашего кода. В противном случае, если другой кодер должен изменить данную хранимую процедуру, им придется полагаться на то, что вызывающий агент действительно завершает процедуру в транзакции. Включение транзакции в рамках процедуры явно определяет вашу транзакцию.

+3

Тому, кто решил забить -1, было бы вежливо, чтобы вы могли рассуждать. –

5

Как и в случае с FYI, Oracle не поддерживает вложенные транзакции, и если вы начинаете транзакцию на внешнем уровне, а затем вызываете серию хранимых процедур, любой хранимый-proc, который выдает коммит, совершает всю транзакцию, поэтому далеко не только транзакция, которую она подстрекала. Поэтому вам необходимо управлять транзакцией за пределами хранимой процедуры при вызове с таких языков, как C#

Просто подумал, что вам может быть интересно, для сравнения.

+0

Он поддерживает автономные_транзакции, хотя позволяет существенно начать новую транзакцию за пределами вашей текущей. Это почти всегда плохая идея. Он также поддерживает точки сохранения. который позволяет частично откатываться, хотя это не то, что я использовал. –

3

Вне или по крайней мере на внешнем уровне API базы данных.

Если вы поручаете внутри каждой хранимой процедуры, то вы, возможно, также автокоммит включена, изображение следующие хранимые процедуры

create_user_with_email_address 
    calls -> create_user 
    calls -> create_email_address 

, если вы внесете в любом CREATE_USER/create_email_address то create_user_with_email_address больше не может быть транзакционные, если create_email_address не удалось, create_user уже был зафиксирован, и у вас были сломанные данные.

Положите транзакцию как можно выше, чтобы сохранить все в ней.

+0

Я не думаю, что это правда, если внешняя транзакция откатывается назад, она также откатывает любые вложенные транзакции. – tpower

+0

Зависит от вашей базы данных, некоторые базы данных не имеют «вложенных транзакций», –

+0

Я думал только о SQL-сервере, но хороший момент +1 – tpower

1

В Sproc мы делаем следующее, потому что если мы просто откатываем его, он подсчитывает количество транзакций во внешних SProcs, которое может генерировать предупреждение обратно в приложение - и если он не ожидает/обрабатывает его, вызвать ошибку приложения.

Однако этот метод только откатывает «локальную» транзакцию, поэтому внешние «вызывающие» должны соответствующим образом интерпретировать возвращаемое значение; альтернативно используйте RAISERROR или аналогичный.

BEGIN TRANSACTION MySprocName_01 
SAVE TRANSACTION MySprocName_02 
... 
IF @ErrorFlag = 0 
BEGIN 
    COMMIT TRANSACTION MySprocName_01 
END 
ELSE 
BEGIN 
    ROLLBACK TRANSACTION MySprocName_02 
    COMMIT TRANSACTION MySprocName_01 
END