1 заметка с тегом

собеседование

Базы данных, транзакции и ACID

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

Пример: транзакция по переводу денег состоит из команд «списать деньги с отправителя», «начислисть деньги адресату».

ACID — это требования к транзакциям и системам, работающим с ними (например, базам данных). ACID требует, чтобы каждая транзакция

  • не зависала в середине пути в случае ошибки, а откатывала все сделанные изменения (атомарность),
  • после своего завершения не оставляла данные неконсистентными (консистентность),
  • не влияла на другие транзакции (на самом деле влияла, но как можно меньше — 4 уровня изолированности),
  • а вся система гарантировала, что выполненные транзакции будут запомнены системой даже при возникновении аварий и форс-мажоров (стойкость, durability).


Подробнее о каждом требовании и с примерами

  1. Atomicity/Атомарность требует, чтобы либо все команды транзакции были выполнены, либо ни одной. То есть транзакция должна действовать как единая атомарная команда.

    На практике атомарность реализуется через версионирование и откаты (rollback) команд транзакции до первоначального состояния базы. Строго говоря, индексы могут обратно не откатиться, но чаще всего СУБД это разруливают сами.
  2. Сonsistency/Консистентность требует, чтобы после завершения транзакции данные оставались консистентными и валидными, т. е. чтобы они не имели логических или технических противоречий.

    Пример: суммарный баланс счетов должен оставаться неизменным (логическая К.), запись одной таблицы не должна ссылаться на удалённый айдишник другой записи (техническая К.).
  3. Isolation/Изолированность — при параллельном выполнении транзакции не должны влиять друг на друга.

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

  4. Durability/Стойкость — если транзакция завершена успешно, то она не может быть отменена даже при авариях, внезапном отключении света в датацентре и проблем в сети. В этом случае база данных должна сама восстановить последние транзакции.

Уровни изолированности в базах данных

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

  1. Read uncommitted — позволяет избежать «потерянных обновлений», когда две транзакции обновляют одно и то же значение/строку.

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

    Пример: транзакция на перевод денег состоит из команды на списание денег с одного счёта и команды пополнения другого счёта. На момент изменения баланса счёта первой транзакцией вторая подобная транзакция встанет в очередь, пока данные не освободятся. Но SELECT-запрос может считать состояние, когда деньги списаны с одного счёта, но на второй ещё не зачислены.

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

    Однако если транзакция содержит две SELECT-команды и во время между ними другая UPDATE-транзакция успешно завершится, то результат этих SELECT-запросов может отличваться: один вернёт состояние до UPDATE-транзакции, второй — после. Важно, что это не «грязное» состояние, а чистое, после успешной транзакции.

  3. Repeatable read (повторяемость чтения) — оба пункта выше + гарантирует, что SELECT-запросы в рамках одной транзакции всегда будут возвращать один и тот же результат, даже если другие транзакции обновляют или удаляют эти же данные.

    Транзакция блокирует все строки, затрагиваемые её командами, включая SELECT, а другие транзакции с SELECT-, UPDATE- и DELETE-запросами к этим данным ждут её завершения. Естественно, это сильно снижает скорость обработки транзакций базой данных.

  4. Serializable — три пункта выше + исключает «фантомные чтения».

    «Фантомное чтение» похоже на проблему с двумя последовательными SELECT-запросами одной транзакции, но возникает, когда между SELECT-запросами была выполнена именно вставка (INSERT). Пример: аггрегационные запросы SELECT SUM(), SELECT COUNT().

    Это максимальный уровень изолированности. При нём транзакции выполняются так, будто других параллельных транзакций не существует.

  5.  



 1 комментарий   2020   acid   database   базы данных   собеседование