Ответ 1
Единственный переносимый способ добиться согласованности между комнатами и тегами и убедиться, что комнаты никогда не возвращаются после того, как они были удалены, блокирует их с помощью SELECT FOR UPDATE
.
Однако в некоторых системах блокировка является побочным эффектом управления concurrency, и вы достигаете тех же результатов, не указав явно FOR UPDATE
.
Чтобы решить эту проблему, Thread 1 должен
SELECT id FROM rooms FOR UPDATE
, тем самым предотвращая удаление Thread 2 сrooms
до тех пор, пока не будет завершен Thread 1. Это правильно?
Это зависит от управления concurrency, используемого вашей базой данных.
-
MyISAM
вMySQL
(и нескольких других старых системах) блокирует всю таблицу в течение всего времени запроса. -
В
SQL Server
запросыSELECT
размещают разделяемые блокировки в записях/страницах/таблицах, которые они исследовали, в то время какDML
запросы помещают блокировки обновлений (которые впоследствии получают повышение до исключительных или пониженных до общих блокировок), Исключительные блокировки несовместимы с общими блокировками, поэтому запросSELECT
илиDELETE
блокируется до тех пор, пока не завершится другой сеанс. -
В базах данных, которые используют
MVCC
(например,Oracle
,PostgreSQL
,MySQL
сInnoDB
), запросDML
создает копию записи (тем или иным способом) и в целом читатели не блокируют писателей и наоборот. Для этих баз данных пригодитсяSELECT FOR UPDATE
: он блокирует либо запросSELECT
, либоDELETE
до тех пор, пока не завершится другой сеанс, как это делаетSQL Server
.
Когда следует использовать
REPEATABLE_READ
изоляцию транзакции по сравнению сREAD_COMMITTED
с помощьюSELECT ... FOR UPDATE
?
Как правило, REPEATABLE READ
не запрещает строки phantom (строки, которые появились или исчезли в другой транзакции, а не были изменены)
-
В версиях
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
" я действительно должен был добавить "из-за побочных эффектов определенной реализации ядра базы данных".