Ответ 1
TL/DR: транзакции по своей сути не предотвращают всех условий гонки. Вам по-прежнему требуется блокировка, обработка прерываний и повторных попыток или другие защитные меры во всех реализациях реальной базы данных. Транзакции - это не секретный соус, который вы можете добавить к своим запросам, чтобы сделать их безопасными из всех concurrency эффектов.
Выделение
Что вы получаете от своего вопроса: I в ACID - isolation. Академически чистая идея заключается в том, что транзакции должны обеспечивать идеальную изоляцию, чтобы результат был таким же, как если бы каждая транзакция выполнялась последовательно. На самом деле это редко случается в реальных реализациях РСУБД; возможности варьируются в зависимости от реализации, и правила могут быть ослаблены с помощью более слабого уровня изоляции, такого как READ COMMITTED
. На практике вы не можете предположить, что транзакции предотвращают все условия гонки, даже при SERIALIZABLE
изоляции.
Некоторые РСУБД имеют более сильные способности, чем другие. Например, PostgreSQL 9.2 и new имеют неплохую изоляцию SERIALIZABLE
, которая обнаруживает большинство (но не все) возможных взаимодействий между транзакциями и прерывает все, кроме одной из конфликтующих транзакций. Таким образом, он может безопасно выполнять транзакции параллельно.
Немногие, если есть 3 системы имеют поистине совершенную изоляцию SERIALIZABLE
, которая предотвращает все возможные расы и аномалии, включая такие проблемы, как блокировка эскалации и блокировка порядка блокировки.
Даже при сильной изоляции некоторые системы (например, PostgreSQL) прерывают конфликтующие транзакции, а не заставляют их ждать и запускать их последовательно. Ваше приложение должно помнить, что он делает, и повторить попытку транзакции. Поэтому, в то время как транзакция помешала concurrency -связанным аномалиям быть сохраненной в БД, она сделала это способом, который не является прозрачным для приложения.
Атомарность
Возможно, основной целью транзакции базы данных является то, что она обеспечивает атомарную фиксацию. Изменения не вступают в силу до момента совершения транзакции. Когда вы совершаете фиксацию, все изменения вступают в силу одновременно с другими транзакциями. Никакая транзакция никогда не увидит только некоторые изменения, сделанные транзакцией 1,2. Аналогично, если вы ROLLBACK
, то ни одна из транзакционных изменений никогда не увидит никакую другую транзакцию; как будто ваша транзакция никогда не существовала.
Что A в ACID.
Прочность
Другим является долговечность - D в ACID. Он указывает, что когда вы совершаете транзакцию, она действительно должна быть сохранена в хранилище, которая выдержит ошибку, например, потерю мощности или внезапную перезагрузку.
Консистенция:
См. wikipedia
Оптимистичное управление concurrency
Вместо использования уровней блокировки и/или высокой изоляции для ORM, таких как Hibernate, EclipseLink и т.д., используется оптимистичный concurrency контроль (часто называемая "оптимистичная блокировка" ) для преодоления ограничений более слабых уровней изоляции при сохранении производительности.
Ключевой особенностью этого подхода является то, что он позволяет вам работать с несколькими транзакциями, что является большим плюсом для систем с большим количеством пользователей и может иметь длительные задержки между взаимодействиями с любым пользователем.
Ссылки
В дополнение к текстовым ссылкам см. раздел документации по PostgreSQL по блокировке, изоляции и concurrency. Даже если вы используете другую РСУБД, вы узнаете многое из понятий, которые она объясняет.
1 Я игнорирую редко реализованный уровень изоляции READ UNCOMMITTED
здесь для простоты; он допускает грязные чтения.
2 Как отмечает @meriton, следствие не обязательно верно. Phantom reads происходит в чем-либо ниже SERIALIZABLE
. Одна часть транзакции, выполняемой в процессе выполнения, не видит некоторых изменений (транзакцией, еще не совершенной), то следующая часть транзакции, выполняемой в процессе выполнения, видит изменения, когда совершается другая транзакция.
3 Ну, IIRC SQLite2 делает это благодаря блокировке всей базы данных при попытке записи, но это не то, что я бы назвал идеальным решением для проблем concurrency.