Пожалуйста, помогите мне разобраться в сценарии использования SELECT ... FOR UPDATE
.
Вопрос 1. Является ли следующий хороший пример того, когда SELECT ... FOR UPDATE
следует использовать?
Дано:
- комнаты [ID]
- теги [id, name]
- room_tags [room_id, tag_id]
- room_id и tag_id - внешние ключи
Приложение хочет вывести список всех комнат и их тегов, но ему необходимо различать комнаты без тегов и комнаты, которые были удалены. Если SELECT ... FOR UPDATE не используется, может произойти следующее:
- Первоначально:
- комнаты содержат
[id = 1]
- теги содержат
[id = 1, name = 'cats']
- room_tags содержит
[room_id = 1, tag_id = 1]
- комнаты содержат
- Поток 1:
SELECT id FROM rooms;
returns [id = 1]
- Поток 2:
DELETE FROM room_tags WHERE room_id = 1;
- Поток 2:
DELETE FROM rooms WHERE id = 1;
- Поток 2: [совершает транзакцию]
- Поток 1:
SELECT tags.name FROM room_tags, tags WHERE room_tags.tag_id = 1 AND tags.id = room_tags.tag_id;
- возвращает пустой список
Теперь поток 1 думает, что у комнаты 1 нет тегов, но на самом деле комната была удалена. Чтобы решить эту проблему, поток 1 должен SELECT id FROM rooms FOR UPDATE
предотвратить удаление потока 2 rooms
до тех пор, пока поток 1 не будет завершен. Это правильно?
Вопрос 2 : Когда следует использовать SERIALIZABLE
изоляцию транзакций, а не READ_COMMITTED
с SELECT ... FOR UPDATE
?
Ожидается, что ответы будут переносимы (не привязаны к базе данных). Если это невозможно, объясните, почему.
REPEATABLE_READ
иREAD_COMMITTED
даже переносные варианты? Единственные результаты, которые я получаю для них, относятся к серверу MSSQLREAD COMMITTED
режима не определяет, действительно ли вы будете видеть записи, зафиксированные другой транзакцией: это только гарантирует, что вы никогда не увидите незафиксированные записи.select ... for update
по-rooms
прежнему можноroom_tags
будет удалить, потому что это отдельные таблицы. Вы хотели спросить,for update
предотвратит ли этот пункт удаление изrooms
?Ответы:
Единственный переносимый способ добиться согласованности между комнатами и тегами и гарантировать, что комнаты никогда не возвращаются после того, как они были удалены, - это заблокировать их с помощью
SELECT FOR UPDATE
.Однако в некоторых системах блокировка является побочным эффектом управления параллелизмом, и вы можете добиться тех же результатов без
FOR UPDATE
явного указания .Это зависит от контроля параллелизма, который использует ваша система базы данных.
MyISAM
inMySQL
(и несколько других старых систем) блокирует всю таблицу на время выполнения запроса.В
SQL Server
,SELECT
запросы в месте , разделяемые блокировки на записи / страницах / таблицах они были допрошены, в то время какDML
запросы место блокировки обновления (которые позже получить звание исключающих или понижены до разделяемых блокировок). Эксклюзивные блокировки несовместимы с разделяемыми блокировками, поэтому любой запросSELECT
илиDELETE
будет блокироваться до тех пор, пока не будет зафиксирован другой сеанс.В базах данных, использование которых
MVCC
(напримерOracle
,PostgreSQL
,MySQL
сInnoDB
),DML
запрос создает копию записи (в той или иной способ) и , как правило читатели не блокируют писателей и наоборот. Для этих баз данных,SELECT FOR UPDATE
бы пригодиться: он будет блокировать либоSELECT
илиDELETE
запрос до другого сеанса фиксаций, так же , какSQL Server
делает.Как правило,
REPEATABLE READ
не запрещает фантомные строки (строки, которые появились или исчезли в другой транзакции, а не были изменены)В
Oracle
и более раннихPostgreSQL
версияхREPEATABLE READ
это фактически синонимSERIALIZABLE
. По сути, это означает, что транзакция не видит изменений, внесенных после ее запуска. Таким образом, в этой настройке последнийThread 1
запрос вернет комнату, как если бы она никогда не удалялась (что может быть, а может и не быть тем, что вы хотели). Если вы не хотите показывать комнаты после того, как они были удалены, вы должны заблокировать строки с помощьюSELECT FOR UPDATE
В
InnoDB
,REPEATABLE READ
иSERIALIZABLE
это разные вещи: читатели вSERIALIZABLE
наборе режима следующего ключа на записях , которые они оценивают, эффективно предотвращающие попутнойDML
на них. Таким образом, вам не нужныSELECT FOR UPDATE
в сериализуемом режиме, но они нужны вREPEATABLE READ
илиREAD COMMITED
.Обратите внимание, что стандарт по режимам изоляции предписывает, что вы не видите определенных причуд в своих запросах, но не определяет, каким образом (с блокировкой или с
MVCC
или иначе).Когда я говорю «вам не нужно
SELECT FOR UPDATE
», мне действительно следовало добавить «из-за побочных эффектов определенной реализации механизма базы данных».источник
SERIALIZABLE
следует использовать в сравненииREAD_COMMITTED
сSELECT ... FOR UPDATE
. Не могли бы вы обновить свой ответ, чтобы отразить этот обновленный вопрос?SELECT FOR UPDATE
в сериализуемом режиме», сInnoDB
. В другихMVCC
системах эти два слова являются синонимами, и они вам действительно нужныSELECT FOR UPDATE
.This depends on the concurrency control your database system is using
: Я думаю, что вы секете волосы. Все случаи, которые вы перечисляете ниже, говорят о том, что комната не удаляетсяSELECT
до конца транзакции. Итак, не следует ли отвечать простоYes
с помощью вспомогательных ссылок ниже?Короткие ответы:
Q1: Да.
Q2: Неважно, что вы используете.
Длинный ответ:
A
select ... for update
будет (как это подразумевается) выбирать определенные строки, но также блокировать их, как если бы они уже были обновлены текущей транзакцией (или как если бы обновление идентификатора было выполнено). Это позволяет вам снова обновить их в текущей транзакции и затем зафиксировать, при этом другая транзакция не сможет каким-либо образом изменить эти строки.С другой стороны, это как если бы следующие два оператора выполнялись атомарно:
Поскольку затронутые строки
my_condition
заблокированы, никакая другая транзакция не может изменить их каким-либо образом, и, следовательно, уровень изоляции транзакции здесь не имеет значения.Также обратите внимание, что уровень изоляции транзакции не зависит от блокировки: установка другого уровня изоляции не позволяет вам обойти блокировку и обновить строки в другой транзакции, которые заблокированы вашей транзакцией.
Какие уровни изоляции транзакции действительно гарантируют (на разных уровнях), так это согласованность данных во время выполнения транзакции.
источник
What transaction isolation levels do guarantee [...] is the consistency of data once transactions are completed.
неправильно подразумевает, что уровни изоляции не влияют на то, что происходит во время транзакции. Я рекомендую пересмотреть этот раздел и предоставить более подробную информацию о том, как они влияют на то, что вы видите (или не видите) во время транзакции.