Что не входит в принципы acid в mysql

Требования ACID на простом языке

Мне нравятся книги из серии Head First O`Reilly — они рассказывают просто о сложном. И я стараюсь делать также.

Когда речь идёт о базах данных, могут всплыть магические слова «Требования ACID». На собеседовании или в разговоре разработчиков — не суть. В этой статье я расскажу о том, что это такое, как расшифровывается ACID и что означает каждая буква.

Требования ACID — набор требований, которые обеспечивают сохранность ваших данных. Что особенно важно для финансовых операций. Мы же не хотим остаться без денег из-за разрыва соединения или ошибки в ПО, не так ли?

Давайте пройдемся по каждой букве ACID и посмотрим на примерах, чем архив лучше 10 разных файлов. И чем транзакция лучше 10 отдельных запросов.

Atomicity — Атомарность

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

Друг познается в беде, а база данных — в работе с ошибками. О, если бы всё всегда было хорошо и без ошибок! Тогда бы никакие ACID были бы не нужны. Но как только возникает ошибка, атомарность становится очень важна.

Допустим, вы решили отправить маме деньги. Когда вы делаете перевод внутри банка, что происходит:

У вас деньги списались

Что не входит в принципы acid в mysql

И допустим, что у нас 2 отдельных запроса. А теперь посмотрим, что будет при возникновении ошибок:

1. У вас на балансе нет нужной суммы — система вывела сообщение об ошибке, но катастрофы не произошло, атомарность тут не нужна.

Что не входит в принципы acid в mysql

2. У мамы заблокирована карточка, истек срок годности — деньги ей не поступили. Запрос отменен. Но минуточку. У вас то они уже списались!

Что не входит в принципы acid в mysql

Ошибка на первом этапе никаких проблем в себе не таит. А вот ошибка на втором. Приводит к потере денег, что явно недопустимо.

Если мы отправляем отдельные запросы, система не может связать их между собой. Запрос упал с ошибкой? Система его отменяет. Но только его, ведь она не знает о том, что запрос «у меня деньги спиши» связан с упавшим «сюда положи»!

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

Что не входит в принципы acid в mysql

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

Consistency — Согласованность

Транзакция, достигающая своего нормального завершения (EOT — end of transaction, завершение транзакции) и, тем самым, фиксирующая свои результаты, сохраняет согласованность базы данных. Другими словами, каждая успешная транзакция по определению фиксирует только допустимые результаты ​ wikipedia

Это свойство вытекает из предыдущего. Благодаря тому, что транзакция не допускает промежуточных результатов, база остается консистентной. Есть такое определение транзакции: «Упорядоченное множество операций, переводящих базу данных из одного согласованного состояния в другое». То есть до выполнения операции и после база остается консистентной (в переводе на русский — согласованной).

Что не входит в принципы acid в mysql

Например, пользователь в системе заполняет карточку:

Телефон — отдельно код страны, города и номер

Источник

ACID. Что под капотом у транзакции

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

Что не входит в принципы acid в mysql

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

Что такое транзакция (transaction)?

Транзакция — это некий набор связанных операций с базой данных.

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

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

С первого лицевого счета происходит списание N-ой суммы денежных средств.

На второй лицевой счет идет зачисление этой же суммы.

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

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

Виды транзакций

Транзакции делят на два вида:

Неявные транзакции, которые предусмотрены на уровне базы данных. Например, БД задает отдельную инструкцию INSERT, UPDATE или DELETE как единицу транзакции.

Явные транзакции — их начало и конец явно обозначаются такими инструкциями, как BEGIN TRANSACTION, COMMIT или ROLLBACK.

В ORM Laravel при использовании фасада DB есть возможность явно указать транзакцию с помощью конструкции DB::transaction(). Если необходимо больше гибкости, можно обратиться к конструкциям DB::beginTransaction(), DB::rollBack(), DB::commit().

Свойства транзакции

Выделяют так называемые «магические» свойства транзакции, которые описываются аббревиатурой «ACID». Каждая буква аббревиатуры означает одно из свойств, о которых мы поговорим ниже.

Atomicity или атомарность (A)

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

Первый запрос выполнится успешно. С первого лицевого счета будет списана N-ая сумма денежных средств.

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

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

Что не входит в принципы acid в mysql

Consistency или согласованность (C)

Согласованность означает, что если до выполнения транзакции данные в БД находятся в неком состоянии «good state»*, то они будут в этом же состоянии и после выполнения транзакции.

*Иными словами, выполняется некий набор условий. Примеры: в таблице countries не должно быть двух строк с названием страны «Российская Федерация»; возраст человека не может быть больше 150 лет.

На самом деле ни одна база данных не может гарантировать свойство согласованности. А всё потому, что поддержание консистентности — это прерогатива приложения, а не БД. База данных лишь предоставляет инструменты для выполнения данного свойства транзакции, например, уникальные ключи, внешние ключи и т.д.

Что не входит в принципы acid в mysql

Isolation или изоляция (I)

Переходим к самому интересному свойству — изоляции. Представим ситуацию, когда в определенный момент времени с системой работают несколько пользователей. Естественно, операции транзакции в БД выполняются параллельно, чтобы ускорить работу системы. Но у параллельной работы транзакций есть свои подводные камни:

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

Но что будет, если две и более операций транзакции в один момент времени начнут работать с одним и тем же набором данных? Возникнет явление, называемое race condition (состояние гонки).

Выделяют несколько эффектов, связанных с этим явлением.

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

Представим, что у клиента банка есть счет, на котором находится 1000 денежных единиц. Транзакции А и В считывают данное значение из БД. Транзакция А должна увеличить данную сумму на 100 денежных единиц, а транзакция В — на 200. Транзакция А увеличивает сумму денежных единиц на счёте на 100 (итого 1100) и записывает значение в БД, транзакция В увеличивает сумму на 200 денежных единиц и записывает в БД (итого 1200). В результате на счете должно оказаться 1300, а по факту имеем 1200 денежных единиц.

Эффект грязного чтения возникает, когда транзакция считывает данные, которые еще не были зафиксированы.

Представим, что транзакция А переводит все деньги клиента на другой счет, но не фиксирует изменения. Транзакция В считывает изменения счёта А, получает 0 денежных единиц на счете и отказывает клиенту в выдаче наличных. Транзакция А прерывается и отменяет перевод между счетами.

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

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

Эффект чтения фантомов возникает, когда набор данных соответствует условиям поиска, но изначально не отображается.

Например, правило согласованности запрещает иметь клиенту более 3 лицевых счетов. Для открытия нового счета транзакция А проверяет все счета клиента банка и в результате получает 2 счета. В этот момент транзакция B открывает еще один счет клиенту и фиксирует изменения (3 счета). Если бы транзакция А повторно проверила количество лицевых счетов клиента, то их оказалось бы 3, и по правилу согласованности открытие нового счета было бы невозможно.

Решение

Для устранения данных эффектов на уровне баз данных предусмотрены уровни изоляции, или transaction isolation levels, которые так или иначе реализованы во многих СУБД. Для примера рассмотрим движок InnoDB в СУБД MySQL:

Read uncommitted – это уровень изоляции, при котором каждая транзакция видит незафиксированные изменения другой транзакции. Справляется с эффектом потерянного обновления, но остаются остальные проблемы: эффекты грязного чтения, неповторяемого чтения, чтения фантомов.

Что не входит в принципы acid в mysql

Все запросы SELECT считывают данные в неблокирующей манере.

Блокирующее чтение (SELECT … FOR UPDATE, LOCK IN SHARE MODE), UPDATE и DELETE блокирует искомые индексные строки. Таким образом, возможна вставка данных в промежутки между индексами. Промежутки блокируются только при проверках на дублирующиеся и внешние ключи.

Read committed — это уровень изоляции, при котором параллельно исполняющиеся транзакции видят только зафиксированные изменения других транзакций. Справляется с эффектами потерянного обновления и грязного чтения, остаются эффекты неповторяемого чтения и чтения фантомов.

Что не входит в принципы acid в mysql

Согласованное чтение не накладывает блокировок, однако считывает данные из свежего снэпшота. В остальном ведёт себя так же, как и read uncommitted.

Repeatable read или snapshot isolation — это уровень изоляции, при котором транзакция не видит изменения данных, прочитанные ей ранее, однако способна прочитать новые данные, соответствующие условию поиска. Справляется с эффектами потерянного обновления, грязного чтения, неповторяемого чтения, остается эффект чтения фантомов.

Что не входит в принципы acid в mysql

Согласованное чтение не накладывает блокировок и считывает данные из снэпшота, который создается при первом чтении в транзакции. Таким образом, одинаковые запросы вернут одинаковый результат.

Блокировка для блокирующего чтения будет зависеть от типа условия:

если условие с диапазоном, например, WHERE (id > 7), то блокируется весь диапазон;

если уникальное, например, WHERE (id = 7), то блокируется одна индексная запись.

Кстати, в InnoDB именно уровень repeatable read используется по умолчанию.

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

Что не входит в принципы acid в mysql

Аналогично repeatable read, но есть интересный момент. Если выключен autocommit (а при явном старте транзакции START TRANSACTION он выключен по умолчанию), то все запросы SELECT превращаются в запросы SELECT … LOCK IN SHARE MODE.

SELECT … LOCK IN SHARE MODE – блокирует считываемые строки на запись.

SELECT … FOR UPDATE – блокирует считываемые строки на чтение.

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

Изоляция — это свойство транзакции, которое позволяет скрывать изменения, внесенные одной операцией транзакции при возникновении явления race condition.

Durability или долговечность (D)

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

Если вы пользуетесь облачными хранилищами, такими как Amazon S3, то могли заметить, что разные тарифы обещают вам разное количество девяток durability. В контексте облака durability означает сохранность ваших данных и то, как они реплицируются. Чем больше копий ваших данных в разных точках мира, тем выше вероятность их не потерять из-за наводнения, землетрясения или нашествия инопланетян. В контексте «ACID» это обычно означает, что после фиксирования данные записываются в постоянное хранилище.

Вывод

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

Источник

Руководство для начинающих: ACID и транзакции БД

Введение

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

Транзакции — это группа операций на чтение/запись, выполняющихся только если все операции из группы успешно выполнены.

Что не входит в принципы acid в mysql

По сути транзакции характеризуются следующими четырьмя свойствами (также известными как ACID):

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

Режим неявной транзакции известен так же как режим autocommit.

Для enterprise систем режим автокоммита следует избегать из-за серьезных проблем с производительностью, и данный режим не позволит включать группу множественных DML в единую атомарную «единицу работы».

Это очень важно понимать и далее мы обсудим каждое из свойств.

Атомарность

Атомарность позволяет объединить единые и независимые операции в «единицу работы», которая работает по принципу «все-или-ничего», успешно выполняющаяся только если все содержащиеся операции успешно выполнятся.

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

Консистентность (согласованность)

Консистентность означает что все требования уникальности были соблюдены для каждой совершенной транзакции. Это подразумевает, что требования по всем ключам (primary и foreign key), типам данных, триггерам успешно пройдены и не было найдено нарушений требования уникальности.

Изоляция

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

Долговечность

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

Для систем сообщений, как JMS, транзакции не являются обязательными. Именно по этой причине в спецификации есть режимы подтверждения вне транзакций.

Операции с файловой системой обычно не контролируются, но если бизнес-требования требуют транзакций для операций с файлами, Вы можете использовать инструмент, такой как XADisk.

В то время как для файловых систем и систем передачи сообщений использование транзакций опционально, то для БД контроль за транзакциями обязателен.

Уровни изолированности

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

Стандарты SQL определяют 4 уровня изолированности:

Все уровни, кроме SERIALIZABLE уровня подвержены аномалии данных (феномен), которые могут произойти согласно следующей схеме:

Isolation LevelDirty readNon-repeatable readPhantom read
READ_UNCOMMITTED — чтение незавершенных транзакцийдадада
READ_COMMITTED — чтение завершенных транзакцийнетдада
REPEATABLE_READ — повторяемое чтениенетнетда
SERIALIZABLE — последовательное чтениенетнетнет

Феномены

Давайте обсудим каждую из аномалий.

Dirty Read («Грязное» чтение)

Что не входит в принципы acid в mysql

«Грязное» чтение происходит когда транзакция может прочитать незаконченные изменения некоторой другой выполняемой транзакции. Явление случается из-за того что нет блокировки предотвращающей это. На изображении сверху можно увидеть что вторая транзакция использует неконсистентное значение первой транзакции, которая впоследствии подверглась «откату». Так как данный эффект возможен только при минимальном уровне изоляции, а по умолчанию используется более высокий уровень изоляции (READ COMMITTED), то в скрипте чтения данных уровень изоляции будет явно установлен как READ UNCOMMITTED. Если вернуть уровень изоляции по умолчанию (READ COMMITTED) для транзакции 2, то поведение поменяется.

Non-repeatable read (Неповторяющееся чтение)

Что не входит в принципы acid в mysql

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

Транзакция 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
SET Value = 42
WHERE >

COMMIT TRAN;

Результат для READ COMMITTEDValue = 1
Value = 42
Мгновенное выполнение
Результат для REPEATABLE READValue = 1
Value = 1
Ожидание завершения транзакции 1

Phantom read (Фантомное чтение)

Что не входит в принципы acid в mysql

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

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

Транзакция 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)
VALUES(100)
COMMIT TRAN;

Результат для 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, большинство СУБД используют разный уровень по умолчанию.

СУБДУровень по умолчанию
OracleREAD_COMMITTED
MySQLREPEATABLE_READ
Microsoft SQL ServerREAD_COMMITTED
PostgreSQLREAD_COMMITTED
DB2CURSOR STABILITY

Обычно, READ_COMMITED является правильным выбором, поскольку даже SERIALIZABLE не может защитить Вас от потери обновлений во время выполнения чтения/записей в разных транзакций и веб-реквестов. Вы должны принять во внимание эту информацию при принятии решения об уровне изоляции в требованиях enterprise систем.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *