Транзакции Транзакции являются фундаментальной концепцией всех систем баз данных. Суть механизма транзакций заключается в объединении нескольких этапов в единую операцию, выполняемую по принципу «все или ничего». Промежуточные состояния между этапами выполнения не видны другим параллельным транзакциям, и в случае возникновения сбоя, препятствующего завершению транзакции, ни один из этапов не отразится на состоянии базы данных.
В качестве примера рассмотрим банковскую базу данных, содержащую сведения о балансах счетов клиентов и общих суммах депозитов в филиалах. Предположим, необходимо зафиксировать перевод в размере $100.00 со счета Алисы на счет Боба. В упрощенном виде последовательность SQL-команд для данной операции может выглядеть следующим образом:
UPDATE accounts SET balance = balance - 100.00
WHERE name = 'Alice';
UPDATE branches SET balance = balance - 100.00
WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Alice');
UPDATE accounts SET balance = balance + 100.00
WHERE name = 'Bob';
UPDATE branches SET balance = balance + 100.00
WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Bob');
Детали этих команд в данном контексте не имеют существенного значения; важным аспектом является то, что для выполнения этой достаточно простой операции требуется несколько отдельных операций обновления. Руководство банка должно быть уверено в том, что либо все эти обновления будут выполнены успешно, либо не будет выполнено ни одно из них. Недопустима ситуация, при которой системный сбой приведет к зачислению 100.00 долларов Бобу без соответствующего списания средств у Алисы. Равным образом, Алиса не будет удовлетворена качеством обслуживания, если средства с ее счета будут списаны без зачисления на счет Боба. Необходим механизм, гарантирующий, что в случае возникновения ошибки на любом этапе операции ни один из промежуточных шагов не будет зафиксирован в системе. Группировка обновлений в Транзакция обеспечивает такую гарантию. Транзакция обладает свойством атомарности: с точки зрения других транзакций она либо выполняется полностью, либо не выполняется вовсе.
Также требуется гарантия того, что после завершения транзакции и получения подтверждения от системы базы данных внесенные изменения будут окончательно сохранены и не будут утеряны даже в случае последующего критического сбоя. Например, при фиксации снятия наличных Бобом необходимо исключить вероятность того, что запись о списании средств с его счета исчезнет из-за сбоя системы сразу после его выхода из банка. Транзакционная база данных гарантирует, что все изменения, внесенные в рамках транзакции, фиксируются в энергонезависимой памяти (т. е. на диске) до того, как транзакция будет объявлена завершенной.
Другим важным свойством транзакционных баз данных, тесно связанным с понятием атомарности обновлений, является изоляция: при одновременном выполнении нескольких транзакций изменения, вносимые одной из них, не должны быть видимы другим транзакциям до их завершения. Например, если одна транзакция выполняет суммирование балансов всех счетов, недопустимо, чтобы она учитывала списание со счета Алисы, но не учитывала зачисление на счет Боба, или наоборот. Таким образом, транзакции должны выполняться по принципу «все или ничего» не только в отношении их окончательного влияния на состояние базы данных, но и в отношении видимости промежуточных изменений в процессе их выполнения. Изменения, внесенные в рамках открытой транзакции, остаются невидимыми для других транзакций до момента её завершения, после чего все обновления становятся видимыми одновременно.
В Digital Q.DataBaseмеханизм транзакции реализуется путем обрамления
SQL-команд транзакции ключевыми словами
BEGIN и COMMIT commands. Таким образом, банковская
транзакция фактически будет иметь следующий вид:
BEGIN;
UPDATE accounts SET balance = balance - 100.00
WHERE name = 'Alice';
-- etc etc
COMMIT;
Если в процессе выполнения транзакции будет принято решение не фиксировать изменения (например, если Баланс Алисы стал отрицательным), можно использовать команду ROLLBACK вместо
COMMIT, в результате чего все внесенные изменения будут отменены.
Digital Q.DataBase фактически рассматривает каждый SQL-оператор как выполняемый внутри транзакции. Если не указана команда BEGIN
,
то каждый отдельный оператор неявно дополняется конструкциями BEGIN и
(в случае успешного завершения) COMMIT . Группа операторов, ограниченная командами BEGIN и COMMIT
иногда называется Блок транзакции.
Некоторые клиентские библиотеки инициируют команды BEGIN и COMMIT
автоматически, что позволяет использовать механизм блоков транзакций без явного вызова команд. См. документацию по используемому программному интерфейсу.
Механизм транзакций позволяет управлять операторами более гибко с помощью точек сохранения. Точки сохранения позволяют выборочно отменять части транзакции, фиксируя остальные изменения. После определения точки сохранения с помощью команды
SAVEPOINT, при необходимости можно выполнить откат к точке сохранения с помощью ROLLBACK TO. Все изменения в базе данных, внесенные между определением точки сохранения и откатом к ней, аннулируются, однако изменения, внесенные до создания точки сохранения, сохраняются.
После отката к точке сохранения она остается определенной, что позволяет выполнять откат к ней многократно. Если же откат к конкретной точке сохранения больше не требуется, ее можно удалить (высвободить), чтобы система могла освободить ресурсы. Следует учитывать, что удаление точки сохранения или откат к ней автоматически удаляет все точки сохранения, которые были определены после нее.
Все эти операции выполняются внутри блока транзакции, поэтому они не видны другим сессиям базы данных. В случае фиксации блока транзакции внесенные изменения становятся видимыми для других сессий как единое целое; если же происходит откат транзакции, изменения не отображаются вовсе.
Вернемся к примеру с банковской базой данных: предположим, что со Счета Алисы списывается 100,00 долларов и зачисляется на Счет Боба, но затем выясняется, что зачисление должно было пройти на Счет Уолли. Данную операцию можно выполнить с использованием точек сохранения следующим образом:
BEGIN;
UPDATE accounts SET balance = balance - 100.00
WHERE name = 'Alice';
SAVEPOINT my_savepoint;
UPDATE accounts SET balance = balance + 100.00
WHERE name = 'Bob';
-- oops ... forget that and use Wally's account
ROLLBACK TO my_savepoint;
UPDATE accounts SET balance = balance + 100.00
WHERE name = 'Wally';
COMMIT;
Данный пример намеренно упрощен, однако использование точек сохранения (savepoints) позволяет реализовать гибкое управление операциями внутри блока транзакции. Более того, ROLLBACK TO является единственным способом восстановить управление блоком транзакции, который был переведен системой в состояние прерывания (aborted state) из-за ошибки, без необходимости полного отката и повторного запуска всей транзакции.