Следует ли указывать транзакции вне хранимой процедуры или внутри?
Мы можем связать вызов хранимой процедуры в транзакции и указать уровень изоляции.
Или мы можем поместить транзакцию внутри хранимой процедуры, указав там уровень изоляции.
Что лучше делать?
Ответы
Ответ 1
Вы должны применять последовательный подход. Имейте в виду, что откат транзакции в хранимой процедуре откатывает любую область транзакций вложенности, включая любую внешнюю область.
Я бы посоветовал вам хранить ваши транзакции вне процедур. Таким образом, вы сохраняете полный контроль.
Ответ 2
Внутри хранимой процедуры, по моему мнению, наиболее подходящее место.
Одним из основополагающих правил хорошей конструкции транзакций является максимально возможное сокращение срока действия транзакции, и поэтому фиксация должна произойти сразу после завершения логики транзакции. Управление транзакцией за пределами хранимой процедуры приведет к неоправданному продлению срока действия транзакции.
Вы также должны учитывать, что определение транзакции в рамках процедуры также обеспечит большую ясность для вашего кода. В противном случае, если другой кодер должен изменить данную хранимую процедуру, им придется полагаться на то, что вызывающий агент действительно завершает процедуру в транзакции. Включение транзакции в рамках процедуры явно определяет вашу транзакцию.
Ответ 3
Подобно FYI, Oracle не поддерживает вложенные транзакции, и если вы начинаете транзакцию на внешнем уровне, а затем вызываете серию хранимых процедур, любой хранимый-proc, который выдает коммит, будет совершать всю транзакцию до сих пор, а не только транзакцию, которую она инициировала. Поэтому вам необходимо управлять транзакцией за пределами хранимой-proc при вызове с таких языков, как С#
Просто подумал, что вам может быть интересно, для сравнения.
Ответ 4
Снаружи или, по крайней мере, во внешнем слое 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 уже был зафиксирован, и у вас были сломанные данные.
Поместите транзакцию как можно выше, чтобы сохранить все в ней.
Ответ 5
Это зависит от бизнес-логики, если SP является атомарным, он должен реализовать свою собственную транзакцию. Если вы этого не сделаете, вы рискуете ошибочным кодом в будущем, не создавая транзакцию переноса. поэтому, отвечая на ваш вопрос, я думаю, что транзакция должна идти внутри SP.
Конечно, нет ничего, что могло бы остановить вас, и атомные SP реализуют свои собственные транзакции, и вне этой сферы могут существовать другие более широкие транзакции.
В общем случае при создании транзакций внутри SP вы уже можете находиться в пределах транзакции, вам нужно закодировать этот экземпляр при выполнении Commit/Rollback.
Ответ 6
В 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