В чем разница между неповторяемым чтением и phantom read?
Я прочитал статью Изоляция (системы баз данных) из Википедии, но у меня есть несколько сомнений. В приведенном ниже примере произойдет следующее: не повторяемый читать и phantom читать?
Транзакция ASELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
ВЫВОД:
1----MIKE------29019892---------5000
Транзакция B
UPDATE USERS SET amount=amount+5000 where ID=1 AND accountno=29019892;
COMMIT;
Транзакция A
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
Еще одно сомнение заключается в том, что в приведенном выше примере должен использоваться уровень изоляции? И почему?
Из Википедии (в котором есть большие и подробные примеры для этого):
Непрерывное чтение происходит, когда во время транзакции строка извлекается дважды, а значения внутри строки отличаются друг от друга.
и
A phantom чтение происходит, когда в ходе транзакции выполняются два идентичных запроса, а набор строк, возвращаемых вторым запросом, отличается от первого.
Простые примеры:
select sum(x) from table;
возвращает другой результат, даже если ни одна из затронутых строк не была обновлена, если строки были добавлены или удалены.В приведенном выше примере, какой уровень изоляции будет использоваться?
Какой уровень изоляции вам нужен, зависит от вашего приложения. Существует высокая стоимость "лучшего" уровня изоляции (например, уменьшенная concurrency).
В вашем примере вы не будете читать phantom, потому что вы выбираете только одну строку (идентифицированную первичным ключом). Вы можете иметь не повторяющиеся чтения, поэтому, если это проблема, вы можете захотеть иметь уровень изоляции, который предотвращает это. В Oracle транзакция A также может выдавать SELECT FOR UPDATE, тогда транзакция B не может изменить строку до тех пор, пока не будет выполнена A.
Простым способом, который мне нравится думать, является:
Оба неповторяющихся и phantom чтения относятся к операциям модификации данных из другой транзакции, которые были зафиксированы после начала транзакции, а затем прочитаны вашей транзакцией.
Непрерывные чтения - это когда ваша транзакция считывает заверенные ОБНОВЛЕНИЯ из другой транзакции. Такая же строка имеет разные значения, чем при начале транзакции.
Phantom чтения аналогичны, но при чтении из объявленных ВСТАВКИ и/или DELETES из другой транзакции. Появляются новые строки или строки, которые исчезли с момента начала транзакции.
Грязные чтения похожи на неповторяющиеся и phantom чтения, но относятся к чтению данных UNCOMMITTED и происходят при чтении UPDATE, INSERT или DELETE из другой транзакции, а другая транзакция еще не передала данные, Он считывает данные "в процессе", которые могут быть неполными и никогда не могут быть выполнены.
Существует разница в реализации между этими уровнями изоляции двух типов.
Для "неповторяющегося чтения" требуется блокировка строк.
Для "phantom read" требуется блокировка с привязкой, даже блокировка таблицы.
Мы можем реализовать эти два уровня, используя двухфазную блокировку.
В системе с неповторяющимися чтениями результат второго запроса транзакции будет отражать обновление в транзакции B - он увидит новую сумму.
В системе, которая позволяет читать phantom, если Transaction B должен был вставить новую строку с ID = 1, Transaction A увидит новую строку при выполнении второго запроса; то есть phantom чтение является частным случаем не повторяемого чтения.
Принятый ответ указывает прежде всего на то, что так называемое различие между ними фактически не имеет значения вообще.
Если "строка извлекается дважды, а значения внутри строки отличаются друг от друга", то они не являются одной и той же строкой (не такой же кортеж в правильной речи RDB), и тогда действительно по определению также случай, сбор строк, возвращаемых вторым запросом, отличается от первого ".
Что касается вопроса "какой уровень изоляции следует использовать", тем больше ваши данные имеют жизненно важное значение для кого-то, где-то, тем больше будет случай, когда Serializable является вашим единственным разумным вариантом.
Грязное чтение: прочитайте НЕОБХОДИМЫЕ данные из других транзакций.
Непрерывное чтение: прочитайте COMMITED данные из запроса UPDATE из другой транзакции.
Phantom читать: читать COMMITED данные из запроса INSERT или DELETE из другой транзакции.
Обратите внимание на то, что UPDATES может быть более частым занятием в некоторых случаях, а не в фактических INSERT или DELETES. В таких случаях остается опасность чтения не повторяющихся чтений - phantom в этих случаях чтение невозможно. Это почему UPDATES обрабатываются иначе, чем INSERT-DELETE, и соответствующая аномалия также называется по-разному.
Существует также дополнительная стоимость обработки, связанная с обработкой для INSERT-DELETES, а не просто обработка UPDATES.
Уровень изоляции TRANSACTION_READ_UNCOMMITTED не предотвращает ничего. Его уровень нулевой изоляции.
Уровень изоляции TRANSACTION_READ_COMMITTED предотвращает только одно, т.е. Грязный читает.
Уровень изоляции TRANSACTION_REPEATABLE_READ предотвращает две аномалии: Грязные чтения и Непрерывные чтения.
Уровень изоляции TRANSACTION_SERIALIZABLE предотвращает все три аномалии: Dirty reads, Non-repeatable reads и phantom читает.
Тогда почему бы просто не установить транзакцию SERIALIZABLE во все времена?
Ну, ответ на этот вопрос: SERIALIZABLE устанавливает очень медленные транзакции, которых мы опять не хотим.
Фактическое потребление времени транзакции имеет следующую скорость:
SERIALIZABLE > REPEATABLE_READ > READ_COMMITTED > READ_UNCOMMITTED.
Таким образом, настройка READ_UNCOMMITTED является самой быстрой.
На самом деле нам нужно проанализировать usecase и определить уровень изоляции, чтобы мы оптимизировали время транзакции, а также предотвратили большинство аномалий.
Обратите внимание, что базы данных по умолчанию имеют параметр REPEATABLE_READ.