3.4. Транзакции#

3.4. Транзакции

3.4. Транзакции

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

Например, рассмотрим базу данных банка, которая содержит балансы различных клиентских счетов, а также общие балансы по депозитам в филиалах. Предположим, что мы хотим перевести платеж в размере $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, которые не будут списаны со счета Алисы. Также Алисе вряд ли понравится, если с ее счета будут списаны деньги, а Боб не получит зачисление. Нужна гарантия, что если что-то пойдет не так в середине операции, то ни одно из уже выполненных действий не вступит в силу. Объединение обновлений в транзакцию обеспечивает эту гарантию. Транзакция считается атомарной: с точки зрения других транзакций, она либо происходит полностью, либо вообще не происходит.

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

Еще одно важное свойство транзакционных баз данных тесно связано с понятием атомарных обновлений: когда несколько транзакций выполняются одновременно, ни одна из них не должна видеть незавершенные изменения, сделанные другими. Например, если одна транзакция занята подсчетом балансов всех филиалов, недопустимо, чтобы она включала списание в филиале Алисы, но не включала зачисление средств в филиале Боба, и наоборот. Таким образом, свойство транзакций « все или ничего» должно относиться не только к сохранению изменений в базе данных, но и к их видимости во время выполнения. Обновления, сделанные открытой транзакцией, невидимы для других транзакций до завершения транзакции, после чего все обновления становятся видимыми одновременно.

В Tantor SE-1С транзакция устанавливается путем окружения SQL-команд транзакции командами BEGIN и COMMIT. Таким образом, банковская транзакция будет выглядеть следующим образом:

BEGIN;
UPDATE accounts SET balance = balance - 100.00
    WHERE name = 'Alice';
-- etc etc
COMMIT;

Если в ходе выполнения транзакции, мы решим не фиксировать изменения (возможно, мы только что заметили, что баланс Алисы стал отрицательным), можно выполнить команду ROLLBACK вместо COMMIT, и все наши изменения до этого момента будут отменены.

Tantor SE-1С на самом деле рассматривает каждый SQL-запрос как выполняющийся в рамках транзакции. Если вы не указываете команду BEGIN, то каждый отдельный запрос имеет неявную команду BEGIN и (в случае успеха) COMMIT, обернутые вокруг него. Группа запросов, окруженных командами BEGIN и COMMIT, иногда называется блоком транзакции.

Примечание

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

Можно управлять операторами в транзакции более ювелирно при помощи точек сохранения (savepoints). Точки сохранения позволяют выборочно отменять одни части транзакции, и фиксировать другие. После определения точки сохранения через 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;

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