Предотвращают ли транзакции базы данных условия гонки? - PullRequest
27 голосов
/ 25 июня 2011

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

// Java/JPA example
em.getTransaction().begin();
User u = em.find(User.class, 123);
u.credits += 10;
em.persist(u); // Note added in 2016: this line is actually not needed
em.getTransaction().commit();

(я знаю, что это может быть записано как один запрос на обновление, но это не всегда так)

Защищен ли этот код от условий гонки?

Меня больше всего интересует MySQL5 + InnoDB, но приветствуются и общие ответы.

Ответы [ 4 ]

22 голосов
/ 28 сентября 2014

TL / DR: транзакции не по своей сути предотвращают все условия гонки. Вам по-прежнему нужны блокировка, обработка прерывания и повторной попытки или другие защитные меры во всех реальных реализациях баз данных. Транзакции не являются секретным соусом, который вы можете добавить к своим запросам, чтобы обезопасить их от всех эффектов параллелизма .

Изоляция

Что вы задаете своим вопросом - это I в КИСЛОТА - изоляция . Академически чистая идея заключается в том, что транзакции должны обеспечивать идеальную изоляцию, чтобы результат был таким же, как если бы каждая транзакция выполнялась последовательно. В действительности это редко имеет место в реальных реализациях RDBMS; возможности варьируются в зависимости от реализации, и правила могут быть ослаблены использованием более слабого уровня изоляции , например READ COMMITTED. На практике вы не можете предполагать, что транзакции предотвращают все условия гонки , даже при SERIALIZABLE изоляции.

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

Мало, если таковые имеются 3 , системы имеют действительно совершенную SERIALIZABLE изоляцию, которая предотвращает все возможные расы и аномалии, включая такие проблемы, как эскалация блокировки и взаимоблокировка упорядочивания блокировки.

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

Атомарность

Возможно, основная цель транзакции базы данных заключается в том, что она обеспечивает атомарную фиксацию . Изменения не вступят в силу, пока вы не совершите транзакцию. Когда вы фиксируете, все изменения вступают в силу в тот же момент, что и другие транзакции. Ни одна транзакция не может увидеть только некоторые изменений, которые совершает транзакция 1,2 . Точно так же, если вы ROLLBACK, то ни одно из изменений транзакции не будет замечено какой-либо другой транзакцией; как будто ваша транзакция никогда не существовала.

Это A в ACID .

Прочность

Еще одна долговечность - D в ACID . Он указывает, что когда вы совершаете транзакцию, она должна быть действительно сохранена в хранилище, которое переживет ошибку, такую ​​как потеря питания или внезапная перезагрузка.

Консистенция:

См. Википедия

Оптимистичный контроль параллелизма

Вместо того, чтобы использовать блокировки и / или высокие уровни изоляции, для ORM, таких как Hibernate, EclipseLink и т. Д., Обычно используется оптимистический контроль параллелизма (часто называемый "оптимистической блокировкой") для преодолеть ограничения более слабых уровней изоляции при сохранении производительности.

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

Ссылки

В дополнение к текстовым ссылкам см. главу документации PostgreSQL о блокировке, изоляции и параллелизме . Даже если вы используете другую СУБД, вы многое узнаете из концепций, которые она объясняет.


1 Я игнорирую редко используемый уровень изоляции READ UNCOMMITTED здесь для простоты; это допускает грязное чтение.

2 Как указывает @meriton, следствие не обязательно верно. Фантомные чтения встречаются во всем, что ниже SERIALIZABLE. Одна часть незавершенной транзакции не видит некоторые изменения (транзакцией, еще не совершенной), затем следующая часть незавершенной транзакции видит изменения, когда другая транзакция фиксирует .

3 Что ж, IIRC SQLite2 делает это благодаря блокировке всей базы данных при попытке записи, но это не то, что я бы назвал идеальным решением проблем параллелизма.

14 голосов
/ 25 июня 2011

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

Многие объектно-реляционные преобразователи (включая поставщиков JPA) также поддерживают оптимистическую блокировку , где конфликты обновления не предотвращаются вбазы данных, но обнаружены на уровне приложения, который затем откатывает транзакцию.Если у вас включена оптимистическая блокировка, типичное выполнение вашего примера кода выдаст следующие sql запросы:

select id, version, credits from user where id = 123;  

Допустим, это возвращает (123, 13, 100).

update user set version = 14, credit = 110 where id = 123 and version = 13;

База данных сообщает нам, сколько строк было обновлено.Если это был один, не было конфликтующих обновлений.Если он был равен нулю, произошло конфликтующее обновление, и поставщик JPA сделает

rollback;

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

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

4 голосов
/ 25 июня 2011

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

1 голос
/ 25 июня 2011

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

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

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

...