Коли використовувати SELECT… ДЛЯ ОНОВЛЕННЯ?


119

Допоможіть мені, будь ласка, зрозуміти приклад використання SELECT ... FOR UPDATE.

Запитання 1 : Чи наведений нижче приклад, коли SELECT ... FOR UPDATEслід використовувати?

Подано:

  • кімнати [ід]
  • теги [id, ім'я]
  • 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?

Очікується, що відповіді будуть портативними (не залежать від бази даних). Якщо це неможливо, поясніть, будь ласка, чому.


2
Які RDBMS ви використовуєте?
Quassnoi

2
@Quassnoi, як згадувалося внизу питання, я шукаю портативне (не конкретне для бази даних) рішення.
Гілі

2
Чи є варіанти REPEATABLE_READі READ_COMMITTEDнавіть портативні варіанти? Єдині результати, які я отримую для них, - це сервер MSSQL
Біллі ONeal

3
@BillyONeal: зауважте, що режими ізоляції гарантують, що ви не бачите химер, які вони не дозволяють, але нічого не говорять про примхи, які вони дозволяють. Це означає, що налаштування, скажімо, READ COMMITTEDрежиму не визначає, чи ви дійсно будете бачити записи, здійснені іншою транзакцією: це лише гарантує, що ви ніколи не побачите незапущені записи.
Quassnoi

3
select ... for updateЗа - roomsяк і раніше дозволяють room_tagsбути видалено , оскільки вони є окремими таблицями. Ви хотіли запитати, чи for updateзапобіжить це застереження від видалення rooms?
Кріс Саксон

Відповіді:


84

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

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


Щоб вирішити цю проблему, Нитка 1 повинна SELECT id FROM rooms FOR UPDATE, тим самим запобігаючи видаленню Нитки 2, roomsпоки Тема 1 не буде виконана. Це правильно?

Це залежить від контролю за одночасністю використання вашої системи баз даних.

  • 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не забороняє фантомні рядки (рядки, які з’явились або зникли в іншій транзакції, а не змінювалися)

  • У 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", я дійсно повинен був би додати "через побічні ефекти певної реалізації бази даних".


1
Останній пункт - суть справи, я думаю: "вам не потрібен ВИБІР ДЛЯ ОНОВЛЕННЯ в серіалізаційному режимі, але вони потрібні в ПОВТОРЕННІ ЧИТАННЯ або ПРОЧИТАНО ЗВ'ЯЗАНІ".
Colin 't Hart

Ти маєш рацію. Друге питання слід було б запитати , коли SERIALIZABLEслід використовувати в порівнянні READ_COMMITTEDз SELECT ... FOR UPDATE. Чи можете ви оновити відповідь, щоб відобразити це оновлене запитання?
Гілі

1
@Gili: "вам не потрібен SELECT FOR UPDATEсеріалізаційний режим", с InnoDB. З іншими MVCCсистемами обидва є синонімами, і вам це потрібно SELECT FOR UPDATE.
Quassnoi

1
Я вважаю, що публікація Коліна відповідає на мої конкретні запитання краще, ніж ваша відповідь, але я ціную всі надані вами посилання. Я прийму відповідь, яка найкраще поєднує два (конкретні відповіді вгорі, підтримуючі посилання внизу).
Гілі

This depends on the concurrency control your database system is using: Я думаю, ти розщеплюєш волоски. Усі випадки, які ви перераховуєте нижче, говорять про те, що кімната не видаляється SELECTдо кінця транзакції. Отож, чи не слід відповідати просто Yesу відповідних посиланнях нижче?
Гілі

33

Короткі відповіді:

Q1: Так.

Q2: Неважливо, яким ви користуєтесь.

Довга відповідь:

Заповіт select ... for update(як випливає з цього) вибирає певні рядки, але також блокує їх так, ніби вони вже були оновлені поточною транзакцією (або як якщо б оновлення особи було виконано). Це дозволяє вам оновити їх знову в поточній транзакції, а потім здійснити фіксацію, не маючи змоги змінити ці рядки жодним чином.

Ще один спосіб дивитися на це - це як би наступні два твердження виконані атомно:

select * from my_table where my_condition;

update my_table set my_column = my_column where my_condition;

Оскільки рядки, на які впливає my_condition, заблоковані, жодна інша транзакція не може їх змінити жодним чином, а значить, рівень ізоляції транзакцій тут не має ніякої різниці.

Зауважте також, що рівень ізоляції транзакцій не залежить від блокування: встановлення іншого рівня ізоляції не дозволяє вам обійти блокування та оновлення рядків в іншій транзакції, які заблоковані транзакцією.

Який рівень ізоляції транзакцій гарантує (на різних рівнях) - це узгодженість даних під час проведення транзакцій.


1
Я думаю, що What transaction isolation levels do guarantee [...] is the consistency of data once transactions are completed.неправильно випливає, що рівні ізоляції не впливають на те, що відбувається під час транзакції. Я рекомендую переглянути цей розділ та надати більш детальну інформацію про те, як вони впливають на те, що ви бачите (або не бачите) під час транзакції.
Гілі

1
Я вважаю, що ваша відповідь відповідає на мої конкретні запитання краще, ніж у Quassnoi, але я ціную всі посилання, які він надав. Я прийму відповідь, яка найкраще поєднує два (конкретні відповіді вгорі, підтримуючі посилання внизу).
Гілі

Блокування та ізоляція взаємозамінно складні. То чи є книги, щоб отримати знання про це?
Чао
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.