Что делает транзакция вокруг одного оператора?


Я понимаю, как транзакция может быть полезна для координации пары обновлений. То, что я не понимаю, - это обертывание отдельных операторов в транзакциях, что составляет 90% от того, что я когда-либо видел. На самом деле, в реальном коде в моем опыте чаще встречается серия логически связанных транзакций, каждая из которых обернута в свою собственную транзакцию, но вся она не обернута в транзакцию.

В MS-SQL, есть ли какая-либо польза от обертывания одного выбирает, один обновления, одиночные вставки или одиночные удаления в транзакции?

Я подозреваю, что это суеверные программирования.

6 55

6 ответов:

Он ничего не делает. Все отдельные операторы SQL (за редкими исключениями, такими как массовые вставки без журнала или усечение таблицы) автоматически "в транзакции", независимо от того, говорите ли вы это явно или нет.. (даже если они вставляют, обновляют или удаляют миллионы строк).

EDIT: на основе комментария @Phillip ниже... В текущих версиях SQL Server даже массовые вставки и усечение таблицы делают запись некоторые данные в журнал транзакций, хотя и не так много, как другие операции делать. Критическое различие с точки зрения транзакций заключается в том, что в этих других типах операций изменяемые данные в таблицах базы данных не находятся в журнале в состоянии, которое позволяет откатить их.

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

единственная функция, которая "начать транзакцию", "зафиксировать транзакцию" и Команды "RollBack Transaction" предоставляют возможность помещать две или более отдельных инструкций SQL в одну транзакцию.

EDIT: (для усиления комментариев меток...) Да, это может быть связано с "суеверным" программированием, или это может быть признаком фундаментального непонимания природы транзакций базы данных. Более благотворительная интерпретация заключается в том, что это просто результат чрезмерного применения последовательности, которая неуместна и еще одна пример эвфемизма Эмерсона, который:

глупая последовательность-это Хобгоблин маленьких умов,
обожаемый маленькими государственными деятелями, философами и богословами

когда-нибудь слышали о "кислотных" требованиях реляционной базы данных? Это "а" означает атомарный, то есть либо оператор работает полностью, либо нет-и пока оператор выполняется,нет другие запросы могут быть сделаны на данные, затронутые этим запросом. BEGIN TRANSACTION / COMMIT "расширяет" эту функцию блокировки на работу выполняется несколькими операторами, но ничего не добавляет к отдельным операторам.

, журнал транзакций базы данных всегда записывается при изменении базы данных (вставка, обновление, удаление). Это не вариант, а факт, который имеет тенденцию раздражать людей. Да, есть wierdness с объемными вставками и режимами восстановления, но он все равно записывается.

Я назову-падение уровней изоляции здесь тоже. Возня с этим повлияет на отдельные команды, но это все равно не приведет к тому, что запрос с объявленной транзакцией будет выполняться иначе, чем "автономный" запрос. (Обратите внимание, что они могут быть очень мощными и очень опасными с несколькими объявленными транзакциями.) Обратите внимание также, что "nolock" делает не применить к вставкам / обновлениям / удалениям -- эти действия всегда требовали блокировки.

для меня обертывание одного оператора в транзакции означает, что у меня есть возможность откатить его, если я, скажем, забуду предложение WHERE при выполнении инструкции ручного одноразового обновления. Это спасло меня несколько раз.

например

--------------------------------------------------------------
CREATE TABLE T1(CPK INT IDENTITY(1,1) NOT NULL, Col1 int, Col2 char(3));
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');

SELECT * FROM T1


--------------------------------------------------------------
/* MISTAKE SCENARIO     (run each row individually) */
--------------------------------------------------------------
BEGIN TRAN YOUR_TRANS_NAME_1;   /* open a trans named YOUR_TRANS_NAME_1 */
    UPDATE T1 SET COL2 = NULL;  /* run some update statement */
    SELECT * FROM T1;       /* OOPS ... forgot the where clause */
ROLLBACK TRAN YOUR_TRANS_NAME_1;    /* since it did bad things, roll it back */
    SELECT * FROM T1;       /* tans rolled back, data restored. */



--------------------------------------------------------------
/* NO MISTAKES SCENARIO (run each row individually) */
--------------------------------------------------------------

BEGIN TRAN YOUR_TRANS_NAME_2;
    UPDATE T1 SET COL2 = 'CBA' WHERE CPK = 4;   /* run some update statement */
    SELECT * FROM T1;               /* did it correctly this time */

COMMIT TRAN YOUR_TRANS_NAME_2           /* commit (close) the trans */

--------------------------------------------------------------

DROP TABLE T1

--------------------------------------------------------------

одним из возможных оправданий является то, что этот единственный оператор может заставить кучу других SQL работать через триггеры, и что они защищают от чего-то плохого там, хотя я ожидаю, что у любой СУБД будет здравый смысл использовать неявные транзакции таким же образом.

другая вещь, о которой я могу думать, заключается в том, что некоторые API позволяют отключить автокоммитирование, и код написан на всякий случай, если кто-то это сделает.

когда вы начинаете явную транзакцию и выдаете DML, ресурсы, заблокированные оператором, остаются заблокированными, и результаты оператора не видны извне транзакции, пока вы вручную не зафиксируете или не откатите ее.

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

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

в этом случае, вы начинаете другой сделки, которая находится запрос блокировки перед первым коммитом, что позволяет избежать состояния гонки

неявные транзакции совершаются или откатываются немедленно после DML оператор завершается или завершается с ошибкой.

SQL Server имеет параметр, который позволяет отключить автоматическую фиксацию для сеанса. Это даже по умолчанию для некоторых клиентов (см. https://docs.microsoft.com/en-us/sql/t-sql/statements/set-implicit-transactions-transact-sql?view=sql-server-2017)

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

Если команды begin tran / commit tran наблюдаются в базе данных (согласно вашему комментарию здесь), также возможно, что фреймворк генерирует их от имени ничего не подозревающего программиста. (Сколько разработчиков внимательно осматривают SQL-код, созданный их фреймворком?)

Я надеюсь, что это все еще актуально, несмотря на то, что вопрос несколько древний.