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