Следует ли указывать транзакции вне хранимой процедуры или внутри? - PullRequest
14 голосов
/ 06 марта 2009

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

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

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

Ответы [ 6 ]

7 голосов
/ 06 марта 2009

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

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

5 голосов
/ 06 марта 2009

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

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

5 голосов
/ 06 марта 2009

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

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

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

4 голосов
/ 06 марта 2009

Снаружи или, по крайней мере, на внешнем уровне 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 уже зафиксирован, и вы нарушили данные.

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

2 голосов
/ 06 марта 2009

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

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

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

1 голос
/ 06 марта 2009

Мы делаем следующее в 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
...