Когда использовать SELECT ... для обновления?



пожалуйста, помогите мне понять прецедент за SELECT ... FOR UPDATE.



Вопрос 1: следующий хороший пример, когда SELECT ... FOR UPDATE следует использовать?



дано:




  • номера[id]

  • теги[id, name]

  • room_tags[room_id, tag_id]


    • room_id и tag_id являются внешними ключами




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




  • изначально:


    • помещения, содержит [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?



ответы, как ожидается, будут портативными (не зависящими от базы данных). Если это невозможно, объясните почему.

635   2  

2 ответов:

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

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


чтобы решить эту проблему, поток 1 должен SELECT id FROM rooms FOR UPDATE, тем самым предотвращая удаление потока 2 из rooms пока Нить 1 выполнена. Это правильно?

это зависит от управления параллелизмом, которое использует ваша система баз данных.

  • MyISAM на MySQL (и несколько других старых систем) блокирует всю таблицу на время запроса.

  • In SQL Server,SELECT запросы помещают общие блокировки на записи / страницы / таблицы, которые они рассмотрели, в то время как DML запросы размещают блокировки обновления (которые позже повышаются до эксклюзивных или понижен до общих блокировок). Эксклюзивные блокировки несовместимы с общими блокировками, поэтому либо SELECT или DELETE запрос будет заблокирован до фиксации другого сеанса.

  • в базах данных, использовать MVCC (типа Oracle,PostgreSQL,MySQL С InnoDB), a DML запрос создает копию записи (тем или иным способом) и обычно читатели не блокируют писателей и наоборот. Для этих баз данных SELECT FOR UPDATE пригодится: он будет блокировать либо SELECT или DELETE запрос до фиксации другого сеанса, так же как SQL Server делает.

когда следует использовать REPEATABLE_READ изоляция транзакций по сравнению с READ_COMMITTED С SELECT ... FOR UPDATE?

как правило, REPEATABLE READ не запрещает фантомные строки (строки, которые появились или исчезли в другой транзакции, а не модифицируется)

  • In Oracle и ранее PostgreSQL версии REPEATABLE READ на самом деле синоним SERIALIZABLE. В основном это означает, что транзакция не видит изменений, внесенных после ее запуска. Так что в этой настройке последний Thread 1 запрос вернет номер, как будто он никогда не был удален (что может быть или не быть тем, что вы хотели). Если вы не хотите показывать номера после их удаления, вы должны заблокировать строки с помощью SELECT FOR UPDATE

  • In InnoDB,REPEATABLE READ и SERIALIZABLE разные вещи: читатели в SERIALIZABLE режим установлен далее-ключевые замки на записи они оценивают, эффективно предотвращая одновременное DML на них. Так что вам не нужно SELECT FOR UPDATE в сериализуемом режиме, но они нужны в REPEATABLE READ или READ COMMITED.

обратите внимание, что стандарт режимов изоляции предписывает, что вы не видите определенных причуд в своих запросах, но не определяете, как (с блокировкой или с MVCC или иначе).

когда я говорю " вам не нужно SELECT FOR UPDATE " Я действительно должен был добавить "из-за побочных эффектов определенной реализации ядра СУБД".

короткий ответ:

Q1: Да.

Q2: не имеет значения, какой вы используете.

ответ:

A select ... for update будет (как это подразумевается) выбирать определенные строки, но также блокировать их, как если бы они уже были обновлены текущей транзакцией (или как если бы обновление идентификатора было выполнено). Это позволяет вам обновить их снова в текущей транзакции, а затем зафиксировать,без другой транзакции, способной изменить эти строки в любом путь.

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

select * from my_table where my_condition;

update my_table set my_column = my_column where my_condition;

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

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

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

Comments

    Ничего не найдено.