Опубликован: 11.12.2006 | Доступ: свободный | Студентов: 5820 / 381 | Оценка: 4.42 / 3.86 | Длительность: 57:15:00
Лекция 19:

Транзакции и блокировка транзакций

Режимы транзакций

Транзакция может начинаться в одном из трех режимов: автофиксация ( autocommit ), явный режим ( explicit ) или неявный режим ( implicit ). По умолчанию для SQL Server принят режим автофиксации. Рассмотрим, что означает каждый из этих режимов.

Режим автофиксации

В режиме автофиксации каждый оператор T-SQL фиксируется по его завершении, и в этом режиме не требуется никаких дополнительных операторов для управления транзакциями. Иными словами, каждая транзакция состоит только из одного оператора T-SQL. Режим автофиксации полезен при выполнении операторов с помощью интерактивной командной строки, утилиты OSQL или анализатора очередей SQL Server Query Аnalyzer, поскольку вам не нужно задавать в явном виде запуск и окончание каждой транзакции. Каждый оператор будет рассматриваться системой SQL Server как отдельная транзакция и будет фиксироваться сразу после его завершения. Режим автофиксации будет использоваться в каждом соединении с SQL Server, пока вы не запустите транзакцию в явном режиме с помощью оператора BEGIN TRANSACTION или пока не укажете неявный режим. По окончании явно заданной транзакции или после отключения неявного режима SQL Server возвращается к режиму автофиксации.

Явный режим

Явный режим используется чаще всего для программных приложений, а также для хранимых процедур, триггеров и сценариев. При запуске группы операторов для выполнения какой-либо задачи вам может потребоваться указание начала и конца данной транзакции, чтобы затем выполнить фиксацию всей группы операторов или отмену (откат) модификаций всей группы. Если вы явно указываете начало и конец транзакции, это означает, что вы используете явный режим, и такую транзакцию называют явной транзакцией. Явная транзакция задается с помощью операторов T-SQL или с помощью функций API. В этом разделе рассматривается только метод T-SQL; функции API выходят за рамки изложения этой книги.

Дополнительная информация. Для получения сведений о явных транзакциях, использующих технологию ADO и OLE-DB, найдите "explicit transactions" (явные транзакции) в Books Online и выберите "Explicit Transactions" в диалоговом окне Topics Found. Отметим, что ODBC API не поддерживает явных транзакций, а только транзакции в неявном режиме и режиме автофиксации.
Практические советы.
Использование явной транзакции

Рассмотрим ситуацию, в которой вам потребовалось бы использование явной транзакции для запуска и окончания задачи. Предположим, что у нас имеется хранимая процедура с именем Place_Order (Поместить_Заказ), которая управляет в базе данных задачей размещения заказа покупателя на какой-либо товар. Эта процедура включает в себя следующие шаги: выбор информации о текущем счете покупателя, ввод идентификационного номера нового заказа и наименования товара, расчет стоимости заказа с учетом налогов, обновление остатка на счете покупателя с учетом общей стоимости и проверка наличия товара на складе.

Для согласованности информации в базе данных нам нужно, чтобы были завершены все эти шаги или не был завершен ни один из этих шагов. Для этой цели мы сгруппируем все операторы, управляющие данной задачей, в одну явную транзакцию. Если эти операторы не будут объединены в одну группу, это может привести к несогласованному состоянию данных. Например, при обрыве соединения клиента с сервером после завершения шага, где вводится номер нового заказа, но до обновления остатка на счете покупателя, в базе данных появится новый заказ для данного покупателя, но без снятия денег со счета покупателя. В этом случае SQL Server фиксирует каждый оператор сразу после его окончания, что оставляет хранимую процедуру незаконченной на момент разъединения сети. Но если все указанные шаги определены в рамках одной явной транзакции, то в случае разъединения SQL Server автоматически выполнит откат всей транзакции, а клиент может затем снова подсоединиться к серверу и повторно выполнить данную процедуру. Более подробную информацию см. в разделе "Откаты транзакций" далее.

Использование явных транзакций, когда ваша задача состоит из нескольких шагов, как в предыдущем примере, также дает преимущества, поскольку SQL Server (независимо от использования вами операторов ROLLBACK ) автоматически выполнит откат ваших транзакций в случае серьезных ошибок, таких как обрыв связи в сети, аварийный сбой (базы данных или клиентской системы) или взаимоблокировка. (Взаимоблокировки рассматриваются в разделе "Блокирование и взаимоблокировки" далее.) Для запуска транзакции используется оператор T-SQL BEGIN TRANSACTION. Чтобы указать конец транзакции, используется COMMIT TRANSACTION или ROLLBACK TRANSACTION. В операторе BEGIN TRANSACTION вы можете дополнительно указать имя транзакции и затем ссылаться на эту транзакцию по имени в операторе COMMIT TRANSACTION или ROLLBACK TRANSACTION. Ниже показан синтаксис этих трех операторов:

BEGIN TRAN[SACTION] [имя_транзакции | @переменная_с_именем_транзакции]
COMMIT [TRAN[SACTION] [имя_транзакции | @переменная_с_именем_транзакции]]
ROLLBACK [TRAN[SACTION] [имя_транзакции | @переменная_с_именем_транзакции
    | имя_точки_сохранения | @переменная_с_именем_точки_сохранения]]
Фиксирование транзакций

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

Все ресурсы, используемые транзакцией, такие как блокировки, освобождаются после фиксирования данной транзакции. Фиксирование транзакции считается успешным в случае успешного завершения каждого из ее операторов. Ниже приводится небольшая транзакция с именем update_state, которая изменяет в таблице publishers (издатели) значение колонки state на XX для всех издателей, у которых в этой колонке содержится значение NULL:

USE pubs
GO
BEGIN TRAN update_state

UPDATE publishers SET state = 'XX'
WHERE state IS NULL
COMMIT TRAN update_state
GO

Запустив эту транзакцию, вы увидите, что это повлияло на две строки. Чтобы вернуть таблицу к ее исходному состоянию (как если бы вместо фиксирования произошел откат), выполните следующую транзакцию:

USE pubs
GO
BEGIN TRAN undo_update_state

UPDATE publishers SET state = NULL
WHERE state = 'XX'
COMMIT TRAN undo_update_state
GO

И снова вы увидите, что это повлияло на две строки. Имена транзакций update_state (модифицировать_состояние) и undo_update_state (отменить_модификацию_состояния), используемые в операторе COMMIT TRAN, игнорируются в SQL Server: имена транзакций используются просто для удобства программиста, чтобы можно было указать имя фиксируемой транзакции. SQL Server автоматически фиксирует последнюю нефиксированную транзакцию, запущенную перед фиксированием, независимо от указания имени транзакции.