Разница между «чтение передано» и «повторное чтение»

246

Я думаю, что вышеупомянутые уровни изоляции так похожи. Может ли кто-нибудь описать с хорошими примерами, в чем главное отличие?

передний
источник
3
Вы должны расширить вопрос и добавить теги для того, на какой «уровень изоляции» вы ссылаетесь (Java и т. Д.). «уровень изоляции» - это несколько двусмысленный термин, и вы, очевидно, спрашиваете ответ для конкретной среды.
27.10.10

Ответы:

565

Чтение совершено это уровень изоляции , который гарантирует , что любой Считанные данные были совершены в момент чтения. Это просто ограничивает читателя от просмотра любого промежуточного, незафиксированного, «грязного» чтения. Не дается никаких обещаний, что если транзакция повторно выдаст чтение, найдет те же данные, данные могут свободно изменяться после их чтения.

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

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

Допустим, у вас есть таблица T со столбцом C с одной строкой, скажем, она имеет значение «1». И учтите, что у вас есть простая задача, подобная следующей:

BEGIN TRANSACTION;
SELECT * FROM T;
WAITFOR DELAY '00:01:00'
SELECT * FROM T;
COMMIT;

Это простая задача, которая выдает два чтения из таблицы T с задержкой в ​​1 минуту между ними.

  • при READ COMMITTED второй SELECT может вернуть любые данные. Параллельная транзакция может обновить запись, удалить ее, вставить новые записи. Второй выбор всегда будет видеть новые данные.
  • при REPEATABLE READ второй SELECT гарантированно отображает как минимум те строки, которые были возвращены из первого SELECT без изменений . Новые строки могут быть добавлены параллельной транзакцией за одну минуту, но существующие строки нельзя удалить или изменить.
  • под SERIALIZABLE читает второй выбор гарантированно увидеть точно те же строки , как первый. Ни одна строка не может быть изменена, ни удалена, ни новые строки не могут быть вставлены параллельной транзакцией.

Если вы будете следовать приведенной выше логике, вы сможете быстро понять, что SERIALIZABLE транзакции, хотя они могут облегчить вам жизнь, всегда полностью блокируют все возможные параллельные операции, поскольку они требуют, чтобы никто не мог изменять, удалять или вставлять какие-либо строки. Уровень изоляции транзакции по умолчанию для области .Net System.Transactionsявляется сериализуемым, и это обычно объясняет ужасную производительность, которая в результате.

И наконец, есть также уровень изоляции SNAPSHOT. Уровень изоляции SNAPSHOT обеспечивает те же гарантии, что и сериализуемые, но не требует, чтобы никакая параллельная транзакция не могла изменить данные. Вместо этого он заставляет каждого читателя видеть свою собственную версию мира (свой собственный «снимок»). Это позволяет очень легко программировать, а также очень масштабируемо, поскольку не блокирует одновременные обновления. Однако это преимущество имеет цену: дополнительное потребление ресурсов сервера.

Дополнительные чтения:

Ремус Русану
источник
24
Я думаю, что есть ошибка выше для REPEATABLE READ: Вы говорите, что существующие строки не могут быть удалены или изменены, но я думаю, что они могут быть удалены или изменены, потому что повторяемое чтение просто читает «снимок», а не фактические данные. Из документации dev.mysql.com/doc/refman/5.0/en/… «Все согласованные чтения в одной транзакции считывают снимок, созданный при первом чтении».
Дерек Лиц
2
@Derek Litz Прав ли я в том, что вы говорите: данные МОГУТ быть изменены третьим лицом во время транзакции, но при чтении все равно будут отображаться «старые» исходные данные, как если бы изменение не было принято место (снимок).
Programster
5
@Cornstalks. Да, чтение фантома может происходить из удалений (или вставок). Да, фантомные чтения могут происходить в повторяемой изоляции чтения (только от вставок). Нет, чтение с фантомом из удалений не может происходить в повторяемой изоляции от чтения. Попробуй это. То, что я говорю, не противоречит приведенной вами документации.
AndyBrown
4
@Cornstalks NP. Я только упомянул об этом, потому что я не был уверен на 100% и должен был глубоко погрузиться, чтобы быть уверенным, кто был прав! И я не хотел, чтобы будущие читатели вводили в заблуждение. Сохраняя комментарии, вероятно, лучше всего придерживаться предложенного. Я уверен, что любой другой, заинтересованный в этом уровне мелких деталей, будет достаточно внимателен, чтобы прочитать все комментарии !!
AndyBrown
12
Спасибо, что не удалили ваши комментарии. Обсуждение помогает соединить больше точек.
Джош
68

Повторяемое чтение

Состояние базы данных сохраняется с начала транзакции. Если вы извлекаете значение в сеансе 1, то обновляете это значение в сеансе 2, и его повторное получение в сеансе 1 возвращает те же результаты. Чтения повторяются.

session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron

session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;

session1> SELECT firstname FROM names WHERE id = 7;
Aaron

Читайте совершено

В контексте транзакции вы всегда получите самое последнее зафиксированное значение. Если вы извлекаете значение в session1, обновляете его в session2, а затем извлекаете его в session1again, вы получите значение, измененное в session2. Это читает последний переданный ряд.

session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron

session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;

session1> SELECT firstname FROM names WHERE id = 7;
Bob

Имеет смысл?

Hazel_arun
источник
Я попытался Repeatable Read в SQL Server 2008 с «установить уровень изоляции повторяемого чтения». Создано два окна запроса SQL. Но не сработало. Зачем?
Адитья Бокаде
1
Почему вторая сессия1 все еще зачитывает Аарона? Не завершена ли транзакция session2? Я знаю это старое, но, возможно, кто-то может пролить свет.
Сонни Чайлдс
9
Я думаю, что Repeatable Read заблокирует второй сеанс до первого сеанса. Так что пример неверный.
Нигон
4
В случае Repeatable Read, когда сеанс 1 читает строку, он устанавливает общую блокировку, которая не позволяет использовать любую эксклюзивную блокировку (для сеанса 2) для обновления, следовательно, данные не могут быть обновлены.
Тахер
Я думаю, что SQL-сервер и MySQL ведут себя по-разному, когда дело доходит до обновления общих строк между двумя транзакциями
user2488286
23

Просто ответ в соответствии с моим прочтением и пониманием этой темы, а ответ @ remus-rusanu основан на следующем простом сценарии:

Существует два процесса A и B. Процесс B читает таблицу X Процесс A записывает таблицу X Процесс B снова читает таблицу X.

  • ReadUncommitted : Процесс B может считывать незафиксированные данные из процесса A и может видеть разные строки на основе записи B. Нет блокировки вообще
  • ReadCommitted : Процесс B может читать ТОЛЬКО зафиксированные данные из процесса A, и он может видеть разные строки на основе только записи COMMITTED B. Можем ли мы назвать это простым замком?
  • RepeatableRead : процесс B будет читать те же данные (строки), что и процесс A. Но процесс А может изменить другие строки. Строка уровня Block
  • Сериализуемый : процесс B будет читать те же строки, что и раньше, а процесс A не сможет прочитать или записать в таблицу. Блок на уровне таблицы
  • Снимок : у каждого процесса есть своя копия, и они работают над этим. У каждого свой взгляд
Мо Заатар
источник
15

Старый вопрос, на который уже есть принятый ответ, но мне нравится думать об этих двух уровнях изоляции с точки зрения того, как они изменяют поведение блокировки в SQL Server. Это может быть полезно для тех, кто отлаживает тупики, как я.

READ COMMITTED (по умолчанию)

Совместно используемые блокировки берутся в SELECT, а затем снимаются после завершения оператора SELECT . Таким образом, система может гарантировать отсутствие грязных операций чтения незафиксированных данных. Другие транзакции могут по-прежнему изменять базовые строки после завершения SELECT и до завершения транзакции.

ПОВТОРЯЕМЫЙ ЧИТАТЬ

Общие блокировки принимаются в SELECT, а затем снимаются только после завершения транзакции . Таким образом, система может гарантировать, что прочитанные вами значения не изменятся во время транзакции (поскольку они остаются заблокированными до завершения транзакции).

Крис Гиллум
источник
13

Попытка объяснить это сомнение с помощью простых диаграмм.

Read Committed: здесь, на этом уровне изоляции, транзакция T1 будет считывать обновленное значение X, зафиксированное транзакцией T2.

Читайте совершено

Повторяемое чтение: на этом уровне изоляции транзакция T1 не будет учитывать изменения, зафиксированные транзакцией T2.

введите описание изображения здесь

vkrishna17
источник
1

Я думаю, что эта картина также может быть полезной, она помогает мне в качестве справки, когда я хочу быстро вспомнить различия между уровнями изоляции (благодаря kudvenkat на YouTube)

введите описание изображения здесь

Иван Павичич
источник
0

Обратите внимание, что повторяемое в повторяемом чтении относится к кортежу, но не ко всей таблице. На уровнях изоляции ANSC может возникнуть аномалия фантомного чтения , что означает, что чтение таблицы с одинаковым предложением where дважды может возвращать разные возвращаемые разные наборы результатов. Буквально это не повторяется .

不辞 长 做 岭南 人
источник
-1

Мое наблюдение за изначально принятым решением.

Под RR (по умолчанию mysql) - если tx открыт и SELECT запущен, другой tx не может удалить ни одну строку, принадлежащую предыдущему набору результатов READ, пока предыдущий tx не будет зафиксирован (фактически, оператор delete в новом tx просто зависнет) Однако следующий tx может удалить все строки из таблицы без каких-либо проблем. Кстати, следующий READ в предыдущем tx будет по-прежнему видеть старые данные, пока не будет зафиксирован.

Санджив Дхиман
источник
2
Вы можете разместить его в разделе комментариев, чтобы ответчик получал уведомления. Таким образом он сможет ответить на ваши наблюдения и внести исправления, если потребуется.
RBT