Избегайте грязных/фантомных чтений при выборе из базы данных

У меня есть две таблицы A и B.

Мои транзакции выглядят так:

  • Чтение -> чтение из таблицы A
  • Запись -> запись в таблицу B, запись в таблицу A

Я хочу избежать грязного/фантомного чтения, так как у меня есть несколько узлов, делающих запрос к одной и той же базе данных.

Вот пример:

  1. Транзакция 1 — обновление происходит в таблице B
  2. Транзакция 2 — чтение происходит в таблице A
  3. Транзакция 1 — обновление происходит в таблице A
  4. Транзакция 2 – завершена
  5. Транзакция 1 – откат

Теперь клиент транзакции 2 имеет грязные данные. Как мне этого избежать?


person Raghunandan J    schedule 13.11.2018    source источник
comment
какую СУБД вы используете? SQL Server, Oracle, MySQL?   -  person Rich Benner    schedule 13.11.2018
comment
Информикс сейчас. планирую перейти на SQL сервер   -  person Raghunandan J    schedule 13.11.2018
comment
Используете ли вы уровень изоляции DIRTY READ в Informix? В informix это единственный способ прочитать незафиксированные данные.   -  person Luís Marques    schedule 13.11.2018
comment
Грязное чтение не рекомендуется. Я хотел знать, есть ли другие решения.   -  person Raghunandan J    schedule 13.11.2018
comment
Informix имеет другие уровни изоляции (есть ограничения в зависимости от типа базы данных). Вы проверили документацию? То, что вы хотите, вероятно, COMMITTED READ или COMMITTED READ LAST COMMITTED.   -  person Luís Marques    schedule 13.11.2018
comment
Схема вашей транзакции не совсем ясна — или, по крайней мере, неясно, как она приводит к проблемам. Шаг 1 не является проблемой, если он завершен до начала шага 2. Шаг 2 не является проблемой, если он завершен до начала шага 3 — или неясно, что это проблема, потому что неясно, что такое TX1 (транзакция 1). Шаг 3 является потенциальной проблемой, если на самом деле шаг 2 не завершен до начала TX2; это зависит от того, какие строки в таблице A обновляются TX1, а какие считываются TX2 и когда. Транзакция 2 завершается без изменения базы данных. Многое зависит от смысла шага 2.   -  person Jonathan Leffler    schedule 14.11.2018
comment
Я расскажу вам о бизнес-использовании - есть несколько клиентов, которые ПОЛУЧАЮТ и ОБНОВЛЯЮТ данные, распределенные по двум таблицам. Я не хочу передавать грязные данные клиенту-2, когда клиент-1 еще не зафиксировал свое ОБНОВЛЕНИЕ. Я пытаюсь добиться этого с двумя таблицами, иначе я денормализую и сделаю это в одной таблице.   -  person Raghunandan J    schedule 14.11.2018


Ответы (1)


Если ваша база данных не зарегистрирована, вы ничего не можете сделать. Выбрав незарегистрированную базу данных, те, кто ее настроил, решили, что такого рода проблемы не являются проблемой. Единственный способ решить проблему здесь — изменить режим базы данных на logged, но это не то, что вы делаете случайно по прихоти — у этого изменения есть много разветвлений.

Предполагая, что ваша база данных зарегистрирована — здесь не имеет значения, является ли это буферизованным ведением журнала или небуферизованным ведением журнала или (в основном) базой данных MODE ANSI — тогда, если вы не установите изоляцию DIRTY READ, вы работаете, используя по крайней мере изоляцию COMMITTED READ (это будет уровень REPEATABLE READ Informix, стандартный уровень SQL SERIALIZABLE, если база данных MODE ANSI).

Если вы хотите гарантировать, что строки данных не изменятся после того, как транзакция их прочтет, вам нужно работать с более высокой степенью изоляции — REPEATABLE READ. (См. НАСТРОЙКА ИЗОЛЯЦИИ подробности в руководстве. "nofollow noreferrer">УСТАНОВИТЬ ТРАНЗАКЦИЮ; в руководстве есть раздел о Сравнение SET ISOLATION и SET TRANSACTION и связанных разделов.) Недостаток использования SET ISOLATION TO REPEATABLE READ (или SET TRANSACTION ISOLATION LEVEL SERIALIZABLE) заключается в том, что дополнительные блокировки, необходимые для уменьшения параллелизм — но дать вам лучшие гарантии о состоянии базы данных.

person Jonathan Leffler    schedule 14.11.2018