В информатике ACID ( атомарность , согласованность , изоляция , долговечность ) — это набор свойств транзакций базы данных , призванных гарантировать достоверность данных, несмотря на ошибки, сбои питания и другие неполадки. В контексте баз данных последовательность операций с базой данных, которая удовлетворяет свойствам ACID (которые можно воспринимать как одну логическую операцию над данными), называется транзакцией . Например, перевод средств с одного банковского счета на другой, даже включающий несколько изменений, таких как дебетование одного счета и кредитование другого, является одной транзакцией.
В 1983 году [1] Андреас Рейтер и Тео Хердер придумали аббревиатуру ACID , основываясь на более ранней работе Джима Грея [2], который назвал атомарность, согласованность и долговечность, но не изоляцию, характеризуя концепцию транзакций. Эти четыре свойства являются основными гарантиями парадигмы транзакций, которая повлияла на многие аспекты разработки систем баз данных .
По данным Грея и Рейтера, система управления информацией IBM поддерживала транзакции ACID еще в 1973 году (хотя аббревиатура была создана позже). [3]
Характеристики этих четырех свойств, определенные Рейтером и Хердером, следующие:
Транзакции часто состоят из нескольких операторов . Атомарность гарантирует, что каждая транзакция рассматривается как единое «единичное целое», которое либо полностью успешно, либо полностью не выполняется: если какой-либо из операторов, составляющих транзакцию, не завершается, вся транзакция не выполняется, а база данных остается неизменной. Атомарная система должна гарантировать атомарность в каждой ситуации, включая сбои питания, ошибки и сбои. [4] Гарантия атомарности предотвращает выполнение обновлений базы данных только частично, что может вызвать большие проблемы, чем полное отклонение всей серии. Как следствие, другой клиент базы данных не может наблюдать выполнение транзакции. В один момент времени она еще не произошла, а в следующий — уже произошла полностью (или ничего не произошло, если транзакция была отменена в процессе).
Согласованность гарантирует, что транзакция может только перевести базу данных из одного согласованного состояния в другое, сохраняя инварианты базы данных : любые данные, записанные в базу данных, должны быть действительными в соответствии со всеми определенными правилами, включая ограничения , каскады , триггеры и любую их комбинацию. Это предотвращает повреждение базы данных незаконной транзакцией. Примером инварианта базы данных является ссылочная целостность , которая гарантирует связь первичного ключа и внешнего ключа . [5]
Транзакции часто выполняются одновременно (например, несколько транзакций одновременно читают и записывают в таблицу). Изоляция гарантирует, что одновременное выполнение транзакций оставляет базу данных в том же состоянии, которое было бы получено, если бы транзакции выполнялись последовательно. Изоляция является основной целью управления параллелизмом ; в зависимости от используемого уровня изоляции, последствия незавершенной транзакции могут быть не видны другим транзакциям. [6]
Долговечность гарантирует, что после того, как транзакция была зафиксирована, она останется зафиксированной даже в случае сбоя системы (например, отключения питания или аварии ). Обычно это означает, что завершенные транзакции (или их последствия) записываются в энергонезависимую память . [7]
Следующие примеры дополнительно иллюстрируют свойства ACID. В этих примерах таблица базы данных имеет два столбца, A и B. Ограничение целостности требует, чтобы значение в A и значение в B в сумме составляло 100. Следующий код SQL создает таблицу, как описано выше:
СОЗДАТЬ ТАБЛИЦУ acidtest ( A INTEGER , B INTEGER , CHECK ( A + B = 100 ));
Атомарность — это гарантия того, что серия операций с базой данных в атомарной транзакции либо все будут выполнены (успешная операция), либо ни одна не будет выполнена (неуспешной операции). Серию операций нельзя разделить, выполнив только некоторые из них, что делает серию операций «неделимой». Гарантия атомарности предотвращает обновления базы данных, происходящие только частично, что может вызвать большие проблемы, чем полное отклонение всей серии. Другими словами, атомарность означает неделимость и неприводимость. [8] В качестве альтернативы мы можем сказать, что логическая транзакция может состоять из нескольких физических транзакций. Пока не будут выполнены все составляющие физические транзакции, логическая транзакция не будет выполнена.
Примером атомарной транзакции является денежный перевод с банковского счета A на счет B. Он состоит из двух операций: снятия денег со счета A и зачисления их на счет B. Мы не хотели бы видеть сумму, снятую со счета A, прежде чем не будем уверены, что она также была переведена на счет B. Выполнение этих операций в атомарной транзакции гарантирует, что база данных остается в согласованном состоянии , то есть деньги не будут ни списаны, ни зачислены, если любая из этих двух операций не будет выполнена. [9]
Согласованность — это очень общий термин, который требует, чтобы данные соответствовали всем правилам проверки. В предыдущем примере проверка — это требование, чтобы A + B = 100. Все правила проверки должны быть проверены для обеспечения согласованности. Предположим, что транзакция пытается вычесть 10 из A, не изменяя B. Поскольку согласованность проверяется после каждой транзакции, известно, что A + B = 100 до начала транзакции. Если транзакция успешно удаляет 10 из A , атомарность будет достигнута. Однако проверка проверки покажет, что A + B = 90 , что несовместимо с правилами базы данных. Вся транзакция должна быть отменена, а затронутые строки откатены к их состоянию до транзакции. Если бы были другие ограничения, триггеры или каскады, каждая отдельная операция изменения была бы проверена таким же образом, как указано выше, перед фиксацией транзакции. Аналогичные проблемы могут возникнуть и с другими ограничениями. Мы могли потребовать, чтобы типы данных как A , так и B были целыми числами. Если бы мы затем ввели, скажем, значение 13.5 для A , транзакция была бы отменена, или система могла бы выдать оповещение в форме триггера (если/когда триггер был бы написан для этого эффекта). Другим примером были бы ограничения целостности, которые не позволили бы нам удалить строку в одной таблице, на первичный ключ которой ссылается по крайней мере один внешний ключ в других таблицах.
Чтобы продемонстрировать изоляцию, мы предполагаем, что две транзакции выполняются одновременно, каждая из которых пытается изменить одни и те же данные. Одна из двух должна дождаться завершения другой, чтобы сохранить изоляцию.
Рассмотрим две транзакции:
В совокупности это четыре действия:
Если эти операции выполняются по порядку, изоляция сохраняется, хотя T 2 должен ждать. Рассмотрим, что произойдет, если T 1 выйдет из строя на полпути. База данных устраняет эффекты T 1 , а T 2 видит только действительные данные.
При чередовании транзакций фактический порядок действий может быть следующим:
Снова рассмотрим, что произойдет, если T 1 выйдет из строя при изменении B на шаге 4. К тому времени, когда T 1 выйдет из строя, T 2 уже изменил A; его нельзя восстановить до значения, которое у него было до T 1, не оставив базу данных недействительной. Это известно как конфликт записи-записи [10] , поскольку две транзакции попытались записать в одно и то же поле данных. В типичной системе проблема будет решена путем возврата к последнему известному хорошему состоянию, отмены неудачной транзакции T 1 и перезапуска прерванной транзакции T 2 из хорошего состояния.
Рассмотрим транзакцию, которая переносит 10 из A в B. Сначала она удаляет 10 из A, затем добавляет 10 к B. В этот момент пользователю сообщается, что транзакция прошла успешно. Однако изменения все еще находятся в очереди в буфере диска , ожидая фиксации на диске. Происходит отключение питания, и изменения теряются, но пользователь предполагает (понятно), что изменения сохраняются.
Обработка транзакции часто требует последовательности операций, которые могут потерпеть неудачу по ряду причин. Например, у системы может не остаться места на дисках или она может израсходовать выделенное ей процессорное время. Существует два популярных семейства методов: опережающее ведение журнала и теневое страничное копирование . В обоих случаях блокировки должны быть получены для всей информации, подлежащей обновлению, и в зависимости от уровня изоляции, возможно, для всех данных, которые могут быть прочитаны. При опережающем ведении журнала долговечность гарантируется путем записи предполагаемого изменения в постоянный журнал перед изменением базы данных. Это позволяет базе данных вернуться в согласованное состояние в случае сбоя. При теневом копировании обновления применяются к частичной копии базы данных, а новая копия активируется при фиксации транзакции.
Многие базы данных полагаются на блокировку для обеспечения возможностей ACID. Блокировка означает, что транзакция помечает данные, к которым она обращается, так что СУБД знает, что нельзя позволять другим транзакциям изменять их, пока первая транзакция не будет успешной или неудачной. Блокировка всегда должна быть получена до обработки данных, включая данные, которые считываются, но не изменяются. Нетривиальные транзакции обычно требуют большого количества блокировок, что приводит к существенным накладным расходам, а также блокировке других транзакций. Например, если пользователь A запускает транзакцию, которая должна прочитать строку данных, которую пользователь B хочет изменить, пользователь B должен дождаться завершения транзакции пользователя A. Двухфазная блокировка часто применяется для гарантии полной изоляции.
Альтернативой блокировке является управление параллелизмом с несколькими версиями , при котором база данных предоставляет каждой транзакции чтения предыдущую, неизмененную версию данных, которые изменяются другой активной транзакцией. Это позволяет читателям работать без получения блокировок, т. е. транзакции записи не блокируют транзакции чтения, а читатели не блокируют писателей. Возвращаясь к примеру, когда транзакция пользователя A запрашивает данные, которые изменяет пользователь B, база данных предоставляет A версию этих данных, которая существовала, когда пользователь B начал свою транзакцию. Пользователь A получает согласованное представление базы данных, даже если другие пользователи изменяют данные. Одна реализация, а именно изоляция снимка , ослабляет свойство изоляции.
Гарантирование свойств ACID в распределенной транзакции в распределенной базе данных , где ни один узел не отвечает за все данные, влияющие на транзакцию, представляет дополнительные сложности. Сетевые соединения могут выйти из строя, или один узел может успешно завершить свою часть транзакции, а затем ему потребуется откатить свои изменения из-за сбоя на другом узле. Протокол двухфазной фиксации (не путать с двухфазной блокировкой ) обеспечивает атомарность для распределенных транзакций , чтобы гарантировать, что каждый участник транзакции согласен с тем, должна ли транзакция быть зафиксирована или нет. [11] Вкратце, на первом этапе один узел (координатор) опрашивает другие узлы (участников), и только когда все отвечают, что они готовы, координатор на втором этапе формализует транзакцию.
Операция, во время которой процессор может одновременно считывать местоположение и записывать его в одной и той же операции шины. Это предотвращает запись или чтение памяти любым другим процессором или устройством ввода-вывода до завершения операции.