acid sql что это
Требования ACID на простом языке
Мне нравятся книги из серии Head First O`Reilly — они рассказывают просто о сложном. И я стараюсь делать также.
Когда речь идёт о базах данных, могут всплыть магические слова «Требования ACID». На собеседовании или в разговоре разработчиков — не суть. В этой статье я расскажу о том, что это такое, как расшифровывается ACID и что означает каждая буква.
Требования ACID — набор требований, которые обеспечивают сохранность ваших данных. Что особенно важно для финансовых операций. Мы же не хотим остаться без денег из-за разрыва соединения или ошибки в ПО, не так ли?
Давайте пройдемся по каждой букве ACID и посмотрим на примерах, чем архив лучше 10 разных файлов. И чем транзакция лучше 10 отдельных запросов.
Atomicity — Атомарность
Атомарность гарантирует, что каждая транзакция будет выполнена полностью или не будет выполнена совсем. Не допускаются промежуточные состояния.
Друг познается в беде, а база данных — в работе с ошибками. О, если бы всё всегда было хорошо и без ошибок! Тогда бы никакие ACID были бы не нужны. Но как только возникает ошибка, атомарность становится очень важна.
Допустим, вы решили отправить маме деньги. Когда вы делаете перевод внутри банка, что происходит:
У вас деньги списались
И допустим, что у нас 2 отдельных запроса. А теперь посмотрим, что будет при возникновении ошибок:
1. У вас на балансе нет нужной суммы — система вывела сообщение об ошибке, но катастрофы не произошло, атомарность тут не нужна.
2. У мамы заблокирована карточка, истек срок годности — деньги ей не поступили. Запрос отменен. Но минуточку. У вас то они уже списались!
Ошибка на первом этапе никаких проблем в себе не таит. А вот ошибка на втором. Приводит к потере денег, что явно недопустимо.
Если мы отправляем отдельные запросы, система не может связать их между собой. Запрос упал с ошибкой? Система его отменяет. Но только его, ведь она не знает о том, что запрос «у меня деньги спиши» связан с упавшим «сюда положи»!
Транзакция же позволяет сгруппировать запросы, то есть фактически показывает базе на взаимосвязи между ними. База сама о связях ничего не знает! Это знаете только вы =)
И если падает запрос внутри транзакции, база откатывает всю транзакцию. И приходит в состояние «как было до начала транзакции». Даже если там внутри было 10 запросов, вы можете спать спокойно — сломался один, откатятся все.
Consistency — Согласованность
Транзакция, достигающая своего нормального завершения (EOT — end of transaction, завершение транзакции) и, тем самым, фиксирующая свои результаты, сохраняет согласованность базы данных. Другими словами, каждая успешная транзакция по определению фиксирует только допустимые результаты wikipedia
Это свойство вытекает из предыдущего. Благодаря тому, что транзакция не допускает промежуточных результатов, база остается консистентной. Есть такое определение транзакции: «Упорядоченное множество операций, переводящих базу данных из одного согласованного состояния в другое». То есть до выполнения операции и после база остается консистентной (в переводе на русский — согласованной).
Например, пользователь в системе заполняет карточку:
Телефон — отдельно код страны, города и номер
Руководство для начинающих: ACID и транзакции БД
Введение
Транзакции повсеместно применяются в современных enterprise системах, обеспечивая целостность данных даже в многопоточных средах. Так давайте начнем сначала с опеределения термина и контекста, в которым обычно применяются транзакции.
Транзакции — это группа операций на чтение/запись, выполняющихся только если все операции из группы успешно выполнены.
По сути транзакции характеризуются следующими четырьмя свойствами (также известными как ACID):
В реляционной БД каждое SQL выражение должно исполняться в пределах транзакции. Без явного определения границ транзакции БД будет использовать неявную транзакцию, которая покрывает каждое SQL выражение. Неявная транзакция начинается до того как выражение запустится и заканчивается (коммит или откат) после того как выражение выполнится.
Режим неявной транзакции известен так же как режим autocommit.
Для enterprise систем режим автокоммита следует избегать из-за серьезных проблем с производительностью, и данный режим не позволит включать группу множественных DML в единую атомарную «единицу работы».
Это очень важно понимать и далее мы обсудим каждое из свойств.
Атомарность
Атомарность позволяет объединить единые и независимые операции в «единицу работы», которая работает по принципу «все-или-ничего», успешно выполняющаяся только если все содержащиеся операции успешно выполнятся.
Транзакция может инкапсулировать изменение состояний. Транзакция должна всегда оставлять систему в консистентном состоянии, независимо от того сколько параллельных транзакций выполняются в любой промежуток времени.
Консистентность (согласованность)
Консистентность означает что все требования уникальности были соблюдены для каждой совершенной транзакции. Это подразумевает, что требования по всем ключам (primary и foreign key), типам данных, триггерам успешно пройдены и не было найдено нарушений требования уникальности.
Изоляция
Во время выполнения транзакции параллельные транзакции не должны оказывать влияние на её результат. Изоляция дает нам преимущество сокрытия нефинальных изменений состояния от внешнего мира, и так же неуспешные транзакции не должны никогда порушить состояние системы. Изоляция достигается через управление параллельным выполнением операций используя пессимистический или оптимистический механизм блокировки.
Долговечность
Успешная транзакция должна всегда изменять состояние системы и прежде чем закончить ее изменения состояния сохраняются в лог транзакций. Если Ваша система внезапно выключится или возникнет перебой с электричеством, тогда все незавершенные транзакции можно воспроизвести.
Для систем сообщений, как JMS, транзакции не являются обязательными. Именно по этой причине в спецификации есть режимы подтверждения вне транзакций.
Операции с файловой системой обычно не контролируются, но если бизнес-требования требуют транзакций для операций с файлами, Вы можете использовать инструмент, такой как XADisk.
В то время как для файловых систем и систем передачи сообщений использование транзакций опционально, то для БД контроль за транзакциями обязателен.
Уровни изолированности
Хотя некоторые СУБД предлагают MVCC, обычно управление параллельным выполнением операций достигается через блокировку. Но, как мы знаем, блокировка увеличивает долю сериализации выполняемого кода, влияя на параллелизацию.
Стандарты SQL определяют 4 уровня изолированности:
Все уровни, кроме SERIALIZABLE уровня подвержены аномалии данных (феномен), которые могут произойти согласно следующей схеме:
Isolation Level | Dirty read | Non-repeatable read | Phantom read |
READ_UNCOMMITTED — чтение незавершенных транзакций | да | да | да |
READ_COMMITTED — чтение завершенных транзакций | нет | да | да |
REPEATABLE_READ — повторяемое чтение | нет | нет | да |
SERIALIZABLE — последовательное чтение | нет | нет | нет |
Феномены
Давайте обсудим каждую из аномалий.
Dirty Read («Грязное» чтение)
«Грязное» чтение происходит когда транзакция может прочитать незаконченные изменения некоторой другой выполняемой транзакции. Явление случается из-за того что нет блокировки предотвращающей это. На изображении сверху можно увидеть что вторая транзакция использует неконсистентное значение первой транзакции, которая впоследствии подверглась «откату». Так как данный эффект возможен только при минимальном уровне изоляции, а по умолчанию используется более высокий уровень изоляции (READ COMMITTED), то в скрипте чтения данных уровень изоляции будет явно установлен как READ UNCOMMITTED. Если вернуть уровень изоляции по умолчанию (READ COMMITTED) для транзакции 2, то поведение поменяется.
Non-repeatable read (Неповторяющееся чтение)
Неповторяющееся чтение проявляется когда повторные чтения в рамках одной транзакции дают разные результаты из-за параллельных транзакций, которые обновили запись, которую мы читаем. Это нежелательно, так как мы в конечном итоге используем устаревшие данные. Это предотвращается размещением разделяемой блокировки (блокировка на чтение) на чтение записи на все протяжении выполнения текущей транзакции.
Транзакция 1 | Транзакция 2 | |
SET TRANSACTION ISOLATION LEVEL READ COMMITTED —SET TRANSACTION ISOLATION LEVEL REPEATABLE READ BEGIN TRAN;SELECT Value FROM Table1 WHERE DELAY ’00:00:10′;SELECT Value FROM Table1 WHERE > UPDATE Table1 COMMIT TRAN; | ||
Результат для READ COMMITTED | Value = 1 Value = 42 | Мгновенное выполнение |
Результат для REPEATABLE READ | Value = 1 Value = 1 | Ожидание завершения транзакции 1 |
Phantom read (Фантомное чтение)
Фантомное чтение происходит когда вторая транзакция вставляет запись, которая подходит по критериям предыдущей выборки первой транзакции. В результате получится, что одни и те же выборки в первой транзакции дают разные множества строк.
Следовательно, мы используем устравшие данные, который могут оказать негативное влияние на работу системы. Это предотвращается с помощью использования блокировки по диапазону или блокировки предикатами.
Транзакция 1 | Транзакция 2 | |
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ —SET TRANSACTION ISOLATION LEVEL SERIALIZABLE BEGIN TRAN; SELECT * FROM Table1 WAITFOR DELAY ’00:00:10′ SELECT * FROM Table1 INSERT INTO Table1 (Value) | ||
Результат для REPEATABLE READ: | — первый SELECT ID: 1; Value: 1 — второй SELECT ID: 1; Value: 1 ID: 2; Value: 100 | Мгновенное выполнение |
Результат для SERIALIZABLE: | — первый SELECT ID: 1; Value: 1 — второй SELECT ID: 1; Value: 1 | Ожидание завершения транзакции 1 |
Уровни изолированности по умолчанию
Даже если SQL стандарт обязывает использовать уровень изоляции SERIALIZABLE, большинство СУБД используют разный уровень по умолчанию.
СУБД | Уровень по умолчанию |
Oracle | READ_COMMITTED |
MySQL | REPEATABLE_READ |
Microsoft SQL Server | READ_COMMITTED |
PostgreSQL | READ_COMMITTED |
DB2 | CURSOR STABILITY |
Обычно, READ_COMMITED является правильным выбором, поскольку даже SERIALIZABLE не может защитить Вас от потери обновлений во время выполнения чтения/записей в разных транзакций и веб-реквестов. Вы должны принять во внимание эту информацию при принятии решения об уровне изоляции в требованиях enterprise систем.
Транзакции, ACID, CAP
Поговорим об базах данных. Сегодня транзакции, ACID и CAP-теорема — теория, которая важна для следующих статей.
Транзакции
Транзакция — это набор действий с данными, объединенный в логическую единицу. Она либо выполняется целиком, либо нет. Классический пример с операцией перевода денег со счета на счет:
Если эти операции выполнять вне транзакции, то ошибка в любой из них оставит оба счета в несогласованном состоянии: например, выйдет так, что деньги снимутся с одного счета, а на другой не придут. С транзакцией таких проблем нет — при ошибке откатятся все операции и для пользователя ничего не изменится.
Все звучит просто, когда с базой данных работает один пользователь: он выполняет транзакции одна за другой и не имеет никаких проблем с тем, что одна транзакция помешает другой. Все меняется, когда пользователей становится много.
Вот что может случиться при параллельном выполнении неизолированных транзакций.
Потерянное обновление
Когда две транзакции записывают разные значения в одну и ту же ячейку, одно из изменений теряется.
Грязное чтение
Когда читаются данные, которые в этот момент изменяются транзакцией, а потом транзакция откатывается и данные исчезают.
Неповторяющееся чтение
Когда несколько раз читаются данные, которые в этот момент изменяются транзакцией — каждый раз данные могут отказаться другими.
Фантомное чтение
Одна транзакция в ходе своего выполнения несколько раз выбирает множество строк по одним и тем же критериям. Другая транзакция в интервалах между этими выборками добавляет или удаляет строки или изменяет столбцы некоторых строк, используемых в критериях выборки первой транзакции, и успешно заканчивается. В результате получится, что одни и те же выборки в первой транзакции дают разные множества строк.
Изоляция транзакций
Чтобы параллельные транзакции могли выполняться, не мешая друг другу, придумали концепцию изоляции транзакций. Всего есть четыре уровня изоляции, но некоторые базы данных вводят свои уровни.
Чтение неподтверждённых данных (read uncommitted)
Самый низкий уровень изоляции. Можно свободно читать незафиксированные изменения других транзакций, но запись идет строго последовательно. Таким образом, исключается только проблема потерянных обновлений: гарантируется, что в итоге в ячейку запишут нужное значение все транзакции по очереди.
Обычно для этого используют блокировку на запись ячеек, предназначенных для изменения в рамках текущей транзакции. На чтение блокировки не ставятся.
Чтение подтверждённых данных (read committed)
Можно свободно читать все изменения своей транзакции и зафиксированные изменения чужих транзакций. Исключаются потерянные обновления и грязное чтение, остаются проблемы неповторяемых чтений и фантомов.
Повторяемое чтение (repeatable read)
Можно читать все изменения только своей транзации. Данные, измененные другими транзакциями, недоступны. Остается только проблема фантомных чтений.
Сериализуемый (serializable)
Транзакции полностью изолируются друг от друга, каждая выполняется так, как будто параллельных транзакций не существует.
Это набор из четырех требований к транзакционной системе, обеспечивающих максимально надежную и предсказуемую работу. Не все базы данных полностью реализуют ACID.
Атомарность (atomicity)
Атомарность гарантирует, что каждая транзакция будет выполнена полностью или не будет выполнена совсем. Не допускаются промежуточные состояния.
Согласованность (consistency)
Согласованность — это требование, подразумевающее, что в результате работы транзакции данные будут допустимыми. Это вопрос не технологии, а бизнес-логики: например, если количество денег на счете не может быть отрицательным, логика транзакции должна проверять, не выйдет ли в результате отрицательных значений.
Изолированность (isolation)
Гарантия того, что параллельные транзакции не будут оказывать влияния на результат других транзакций. Мы разобрались с изоляцией выше.
Долговечность (durability)
Изменения, получившиеся в результате транзакции, должны оставаться сохраненными вне зависимости от каких-либо сбоев. Иначе говоря, если пользователь получил сигнал о завершении транзакции, он может быть уверен, что данные сохранены.
CAP-теорема
Она гласит, что в распределенной системе можно обеспечить только два свойства из трех: согласованность, доступность и устойчивость к разделению. Помогает понимать, как конкретная распределенная система будет работать и чего от нее ожидать.
Согласованность данных (consistency)
Когда во всех узлах в каждый момент времени данные согласованы друг с другом, то есть не противоречат друг другу. Если в одном из узлов в ячейке базы данных есть данные, такие же данные есть на всех остальных узлах.
Доступность (availability)
Когда любой запрос может быть обработан системой, вне зависимости от ее состояния.
Устойчивость к разделению (partition tolerance)
Когда расщепление системы на несколько изолированных секций не приводит к некорректному отклику от каждой из секций: отвалилась сеть между двумя узлами, но каждый из них может корректно отвечать своим клиентам.
Все распределенные базы данных так или иначе в лучшем случае реализуют два свойства из трех, жертвуя оставшимся.
В следующей статье — о редких базах данных, которых вы не увидите в обычных проектах. Там нам и пригодится вся эта теория.
Это тоже база данных, но ручная
Поговорим об базах данных. Сегодня транзакции, ACID и CAP-теорема — теория, которая важна для следующих статей.
Транзакции
Транзакция — это набор действий с данными, объединенный в логическую единицу. Она либо выполняется целиком, либо нет. Классический пример с операцией перевода денег со счета на счет:
Если эти операции выполнять вне транзакции, то ошибка в любой из них оставит оба счета в несогласованном состоянии: например, выйдет так, что деньги снимутся с одного счета, а на другой не придут. С транзакцией таких проблем нет — при ошибке откатятся все операции и для пользователя ничего не изменится.
Все звучит просто, когда с базой данных работает один пользователь: он выполняет транзакции одна за другой и не имеет никаких проблем с тем, что одна транзакция помешает другой. Все меняется, когда пользователей становится много.
Вот что может случиться при параллельном выполнении неизолированных транзакций.
Потерянное обновление
Когда две транзакции записывают разные значения в одну и ту же ячейку, одно из изменений теряется.
Грязное чтение
Когда читаются данные, которые в этот момент изменяются транзакцией, а потом транзакция откатывается и данные исчезают.
Неповторяющееся чтение
Когда несколько раз читаются данные, которые в этот момент изменяются транзакцией — каждый раз данные могут отказаться другими.
Фантомное чтение
Одна транзакция в ходе своего выполнения несколько раз выбирает множество строк по одним и тем же критериям. Другая транзакция в интервалах между этими выборками добавляет или удаляет строки или изменяет столбцы некоторых строк, используемых в критериях выборки первой транзакции, и успешно заканчивается. В результате получится, что одни и те же выборки в первой транзакции дают разные множества строк.
Изоляция транзакций
Чтобы параллельные транзакции могли выполняться, не мешая друг другу, придумали концепцию изоляции транзакций. Всего есть четыре уровня изоляции, но некоторые базы данных вводят свои уровни.
Чтение неподтверждённых данных (read uncommitted)
Самый низкий уровень изоляции. Можно свободно читать незафиксированные изменения других транзакций, но запись идет строго последовательно. Таким образом, исключается только проблема потерянных обновлений: гарантируется, что в итоге в ячейку запишут нужное значение все транзакции по очереди.
Обычно для этого используют блокировку на запись ячеек, предназначенных для изменения в рамках текущей транзакции. На чтение блокировки не ставятся.
Чтение подтверждённых данных (read committed)
Можно свободно читать все изменения своей транзакции и зафиксированные изменения чужих транзакций. Исключаются потерянные обновления и грязное чтение, остаются проблемы неповторяемых чтений и фантомов.
Повторяемое чтение (repeatable read)
Можно читать все изменения только своей транзации. Данные, измененные другими транзакциями, недоступны. Остается только проблема фантомных чтений.
Сериализуемый (serializable)
Транзакции полностью изолируются друг от друга, каждая выполняется так, как будто параллельных транзакций не существует.
Это набор из четырех требований к транзакционной системе, обеспечивающих максимально надежную и предсказуемую работу. Не все базы данных полностью реализуют ACID.
Атомарность (atomicity)
Атомарность гарантирует, что каждая транзакция будет выполнена полностью или не будет выполнена совсем. Не допускаются промежуточные состояния.
Согласованность (consistency)
Согласованность — это требование, подразумевающее, что в результате работы транзакции данные будут допустимыми. Это вопрос не технологии, а бизнес-логики: например, если количество денег на счете не может быть отрицательным, логика транзакции должна проверять, не выйдет ли в результате отрицательных значений.
Изолированность (isolation)
Гарантия того, что параллельные транзакции не будут оказывать влияния на результат других транзакций. Мы разобрались с изоляцией выше.
Долговечность (durability)
Изменения, получившиеся в результате транзакции, должны оставаться сохраненными вне зависимости от каких-либо сбоев. Иначе говоря, если пользователь получил сигнал о завершении транзакции, он может быть уверен, что данные сохранены.
CAP-теорема
Она гласит, что в распределенной системе можно обеспечить только два свойства из трех: согласованность, доступность и устойчивость к разделению. Помогает понимать, как конкретная распределенная система будет работать и чего от нее ожидать.
Согласованность данных (consistency)
Когда во всех узлах в каждый момент времени данные согласованы друг с другом, то есть не противоречат друг другу. Если в одном из узлов в ячейке базы данных есть данные, такие же данные есть на всех остальных узлах.
Доступность (availability)
Когда любой запрос может быть обработан системой, вне зависимости от ее состояния.
Устойчивость к разделению (partition tolerance)
Когда расщепление системы на несколько изолированных секций не приводит к некорректному отклику от каждой из секций: отвалилась сеть между двумя узлами, но каждый из них может корректно отвечать своим клиентам.
Все распределенные базы данных так или иначе в лучшем случае реализуют два свойства из трех, жертвуя оставшимся.
В следующей статье — о редких базах данных, которых вы не увидите в обычных проектах. Там нам и пригодится вся эта теория.