Автор статьи: Роман Козлов

Руководитель курса BI-аналитика

Введение

Транзакция - достаточно обширное понятие, которое используется в разных сферах жизни. Существует банковская транзакция - это операция, которая состоит в переводе денежных средств с одного счёта на другой. Или бывает банкоматная транзакция – выдача денег либо проведение иной операции с помощью терминала. В юриспруденции понятию «транзакция» придается значение схожее со значением понятия «сделка», а в психологии - это факт коммуникации между людьми (трансакция).

Наконец, для информационных технологий «транзакция» - это последовательность (одна или несколько) операций по работе с данными. Чтобы организовать правильный обмен данными к транзакциям и транзакционным системам применяются некоторые требования, которые легли в основу архитектуры современных баз данных.

Чтобы подробно изучить эти требования, обратимся к простому бытовому примеру.

Атомарность

Предположим, мы переводим средства с одного банковского счета на другой. Эта операция состоит из нескольких действий: первое - начало транзакции в ходе которого устанавливается соединение между счетами, далее идёт снятие определенной суммы (например, 300 рублей) со счёта №1, потом - добавление этой же суммы на счёт №2 и стадия завершения в конце транзакции, которую рассмотрим чуть подробнее ниже. Представим себе ситуацию, по которой зачисление средств не прошло или выполнилось с ошибкой. В таком случае, необходимо вернуть средства на счёт №1. В этом заключается первое требование к транзакционным системам, которое называется атомарностью.

Атомарность (Atomicity) вкратце описывается принципом «всё, или ничего». Это означает, что каждая транзакция должна выполняться полностью или не выполняться совсем.  У транзакции нет промежуточных состояний, т.е. она всегда является завершенной. У завершения транзакции есть 2 сценария: подтверждение (commit) и откат (rollback). Возвращаясь к случаю, когда средства сняты с банковского счета №1 и не поступили на счёт №2, в таком случае завершением транзакции станет rollback транзакции и возврат средств обратно на счёт №1. Если операции, входящие в транзакцию выполнены, происходит commit выполненных изменений.

Консистентность

После того как транзакция зафиксировала результаты и перевод средств с одного счёта на другой осуществлён, мы перевели нашу базу данных из одного состояния, в котором пользователь счета №1 был на 300 рублей богаче, а пользователь счёта №2 на 300 рублей беднее, в обратное состояние. При этом, деньги не появились из ниоткуда, т.е база внутри себя осталась согласованной или консистентной. Требование консистентности (Consistency) является вторым к транзакционным системам и логически вытекает из требования атомарности, т.е. каждая выполненная транзакция фиксирует только допустимые результаты. Если со счёта №1 снято 300 рублей, на счёт №2 не должно прийти 200 или 400 рублей, что также предусматривается требованиями консистентности. В этом смысле, данное требование также схоже с законом сохранения энергии в естественных науках.

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

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

Изолированность

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

В случае параллельного выполнения транзакций разными пользователями возникают различные проблемы. Например, если с того же счёта №1, на котором лежит 300 рублей, идёт параллельное выполнение 2-ух транзакций. По одной мы списываем 200 рублей, по другой - начисляем 200 рублей. Если во время выполнения начисления 200 рублей, списание не успело пройти, на счёте мы увидим 500 рублей. Первая транзакция в этом случае потеряется. Такая проблема называется потерянным обновлением.

Еще пример, мы списываем все 300 рублей с того же счёта №1. В этот момент другой пользователь запросил данные с этого счёта и увидел, что на нём осталось 0 рублей. Однако, мы откатили транзакцию по снятию 300 рублей и деньги вернулись на счёт. Получается, другой пользователь получил ошибочные данных о состоянии счёта №1. Это называется «грязным» чтением.

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

Чтобы избежать таких проблем с транзакциями, вводится требование на изолированность (Isolation) для других пользователей. Есть несколько уровней изоляции транзакций, но все они сводятся к блокировке действий одного пользователя, при выполнении изменения или чтения данных другим пользователем. Иногда изолированности транзакций добиваются не введением блокировок, а с помощью версифицирования. Проще говоря, пока записывающая транзакция не сделает commit изменений, остальные пользователи читают старую версию записи и не блокируются.

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

Устойчивость

Наконец, транзакционная система должна обладать устойчивостью (Durability). Это означает то, что если произошёл перевод 300 рублей с одного счёта на другой счёт, и операция прошла успешно, мы должны быть застрахованы от того, что никакие сбои или проблемы с оборудованием не повлияют на эту транзакцию. В итоге, если соединить первые буквы этих четырех требований к транзакционным системам, мы получаем акроним ACID, который можно схематично изобразить следующим образом (рис.1).

 Рисунок 1. ACID (схема)
Рисунок 1. ACID (схема)

Заключение

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

Требования ACID являются фундаментальными основами устройства реляционных СУБД и обеспечивают наиболее надёжную и предсказуемую работу с данными.

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

Комментарии (4)


  1. panzerfaust
    00.00.0000 00:00

    Требование консистентности (Consistency) является вторым к транзакционным системам и логически вытекает из требования атомарности, т.е. каждая выполненная транзакция фиксирует только допустимые результаты

    На самом деле вы тут повторяете принцип атомарности, только другими словами. Потому вам и кажется, что вытекает. СУБД вкладывает в понятие допустимости совсем не то, что можете вкладывать вы, как владелец продукта или разработчик.

    Да, значению банковского счета нельзя присвоить отрицательное число, если так указано в схеме. А вот сделать что-то вроде update account set money_amount = 0 where 1=1 джвижок СУБД вам не запретит, несмотря ни на какой ACID. Потому есть мнение, что буква C была добавлена в акроним "чтобы красивее было". А в действительности задача поддержания согласованности лежит на бизнес-логике приложения, а не на СУБД.


    1. zzzzzzerg
      00.00.0000 00:00
      -1

      Да, значению банковского счета нельзя присвоить отрицательное число, если так указано в схеме

      Вот это же и есть согласованность.


    1. ZloyVampir
      00.00.0000 00:00
      -1

      Бытует мнение, что буковка C на уровне БД отвечает за ссылочную целостность, а не за консистентность уровня бизнес-логики.


  1. VVitaly
    00.00.0000 00:00
    +2

    1) Фраза "Некоторые транзакции выполняются мгновенно, а выполнение некоторых может занимать от нескольких минут до нескольких часов." не очень согласуется с заголовком "Принципы работы OLTP-систем"
    2) Утверждение "В течении выполнения транзакции система будет оставаться несогласованной." для транзакционных ACID систем - оксюморон, хотя ряд систем не гарантирующих 100% ACID (где жертвуют гарантированной 100% атомарностью или 100% консистентностю, обычно ради повышенной производительности) тоже называют себя "транзакционными".