Следует ли указывать транзакции вне хранимой процедуры или внутри?

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

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

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

Ответы

Ответ 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