Связь уровней изоляции транзакций с блокировками таблицы

105

Я читал про 4 уровня изоляции:

Isolation Level       Dirty Read    Nonrepeatable Read  Phantom Read  
READ UNCOMMITTED      Permitted       Permitted           Permitted
READ COMMITTED              --        Permitted           Permitted
REPEATABLE READ             --             --             Permitted
SERIALIZABLE                --             --              --

Я хочу понять блокировку каждой транзакции в таблице.

READ UNCOMMITTED - no lock on table
READ COMMITTED - lock on committed data
REPEATABLE READ - lock on block of sql(which is selected by using select query)
SERIALIZABLE - lock on full table(on which Select query is fired)

Ниже приведены три явления, которые могут возникнуть при изоляции транзакции.
Грязное чтение - нет блокировки
Неповторяющееся чтение - нет грязного чтения в качестве блокировки зафиксированных данных
Фантомное чтение - блокировка блока sql (который выбирается с помощью запроса выбора)

Я хочу понять, где мы определяем эти уровни изоляции: только на уровне jdbc / hibernate или также в БД

PS: Я просмотрел ссылки в уровнях изоляции в oracle , но они выглядят неуклюже и говорят о конкретной базе данных

Ученик
источник
3
Это полностью зависит от базы данных. В разных базах данных могут использоваться разные алгоритмы уровней изоляции. Некоторые могут использовать MVCC (без блокировок на выборочные запросы), некоторые используют строгую двухфазную блокировку (разделяемые и эксклюзивные блокировки).
brb tea

Ответы:

158

Я хочу понять блокировку каждой транзакции в таблице.

Например, у вас есть 3 параллельных процесса A, B и C. A запускает транзакцию, записывает данные и выполняет фиксацию / откат (в зависимости от результатов). B просто выполняет SELECTинструкцию для чтения данных. C читает и обновляет данные. Все эти процессы работают на одном столе T.

  • ПРОЧИТАЙТЕ НЕОБХОДИМО - на столе нет блокировки. Вы можете читать данные в таблице во время записи в нее. Это означает, что A записывает данные (незафиксированные), а B может читать эти незафиксированные данные и использовать их (для любых целей). Если A выполняет откат, B все еще считал данные и использовал их. Это самый быстрый, но самый небезопасный способ работы с данными, поскольку может привести к дырам в данных в физически не связанных таблицах (да, две таблицы могут быть логически, но не физически связаны в реальных приложениях = \).
  • READ COMMITTED - заблокировать зафиксированные данные. Вы можете прочитать только зафиксированные данные. Это означает, что A записывает данные, а B не может прочитать данные, сохраненные A, пока A не выполнит фиксацию. Проблема здесь в том, что C может обновлять данные, которые были прочитаны и использованы на B, и у клиента B не будет обновленных данных.
  • REPEATABLE READ - блокировка блока SQL (который выбирается с помощью запроса выбора). Это означает, что B считывает данные при определенных условиях, например WHERE aField > 10 AND aField < 20, A вставляет данные, aFieldзначение которых находится в диапазоне от 10 до 20, затем B считывает данные снова и получает другой результат.
  • SERIALIZABLE - блокировка полной таблицы (для которой запущен запрос Select). Это означает, что B читает данные, и никакая другая транзакция не может изменять данные в таблице. Это наиболее безопасный, но самый медленный способ работы с данными. Кроме того, поскольку простая операция чтения блокирует таблицу , это может привести к серьезным проблемам при производстве: представьте, что таблица T является таблицей Invoice, пользователь X хочет знать счета за день, а пользователь Y хочет создать новый счет, поэтому пока X выполняет чтение счетов, Y не может добавить новый счет (а когда дело касается денег, люди действительно злятся, особенно начальство).

Я хочу понять, где мы определяем эти уровни изоляции: только на уровне JDBC / hibernate или также в БД.

Используя JDBC, вы определяете его с помощью Connection#setTransactionIsolation.

Использование гибернации:

<property name="hibernate.connection.isolation">2</property>

куда

  • 1: ПРОЧИТАТЬ НЕПРЕРЫВНО
  • 2: ПРОЧИТАТЬ ЗАВЕРШЕНО
  • 4: ПОВТОРНОЕ ЧТЕНИЕ
  • 8: СЕРИАЛИЗИРУЕМЫЙ

Конфигурация гибернации взята отсюда (извините, это на испанском языке).

Кстати, вы можете установить уровень изоляции и на РСУБД:

и так далее...

Луиджи Мендоса
источник
docs.oracle.com/cd/B12037_01/server.101/b10743/consist.htm Просто добавлю для Oracle: можно установить уровень изоляции транзакции, используя один из этих операторов в начале транзакции: SET TRANSACTION ISOLATION УРОВЕНЬ ПРОЧИТАННЫЙ ЗАВЕРШЕН; УСТАНОВИТЬ УРОВЕНЬ ИЗОЛЯЦИИ ПЕРЕДАЧИ ПО СЕРИИ УСТАНОВИТЬ СДЕЛКУ ТОЛЬКО ДЛЯ ЧТЕНИЯ;
Learner
2
Более того, чтобы сэкономить сетевые ресурсы и затраты на обработку при начале каждой транзакции с помощью оператора SET TRANSACTION, вы можете использовать оператор ALTER SESSION для установки уровня изоляции транзакции для всех последующих транзакций: ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE; ALTER SESSION SET ISOLATION_LEVEL READ COMMITTED;
Learner
12
Что касается REPEATABLE READ - я думаю, что лучший пример для демонстрации этого заключается в следующем: B запускает транзакцию, читает данные в блоке sql, WHERE aField> 10 AND aField <20, эти данные блокируются до завершения транзакции. A пытается обновить эти данные, но ждет из-за блокировки. Теперь, когда B снова прочитает эти данные в той же транзакции, он гарантированно прочитает те же данные, потому что они заблокированы. Поправьте меня если я ошибаюсь.
BornToCode
1
@LuiggiMendoza По общему принципу, уровни изоляции - это только грязное чтение , неповторяющееся чтение и фантомные строки . Блокировки (S2PL) или MVCC - это реализации для разных производителей.
brb tea
4
@LuiggiMendoza - я не был точен, должно быть так - данные, которые читает B, не изменяются, но последующие выборки, сделанные B, могут вернуть больше строк. Это потому, что A не может изменять строки, которые уже прочитаны B , пока A не освободит их. Однако A может вставлять новые строки, которые соответствуют условию where (и поэтому в следующий раз, когда A выполнит выбор, он получит другой результат с большим количеством строк - фантомное чтение).
BornToCode
9

Как говорит brb tea, это зависит от реализации базы данных и используемого алгоритма: MVCC или двухфазная блокировка.

CUBRID (СУБД с открытым исходным кодом) объясняет идею этих двух алгоритмов:

  • Двухфазная блокировка (2PL)

Первый - когда транзакция T2 пытается изменить запись A, она знает, что транзакция T1 уже изменила запись A, и ждет, пока транзакция T1 не будет завершена, потому что транзакция T2 не может знать, будет ли транзакция T1 зафиксирована или откатана. назад. Этот метод называется двухфазной синхронизацией (2PL).

  • Управление многоверсионным параллелизмом (MVCC)

Другой - разрешить каждой из них, транзакциям T1 и T2, иметь свои собственные измененные версии. Даже когда транзакция T1 изменила запись A с 1 на 2, транзакция T1 оставляет исходное значение 1 как есть и записывает, что версия транзакции T1 записи A равна 2. Затем следующая транзакция T2 изменяет запись A. от 1 до 3, а не от 2 до 4, и пишет, что версия транзакции T2 для записи A - 3.

Когда транзакция T1 откатывается, не имеет значения, применяется ли 2, версия транзакции T1, к записи A. После этого, если транзакция T2 будет зафиксирована, 3, версия транзакции T2, будет применена к записи A. Если транзакция T1 фиксируется до транзакции T2, запись A изменяется на 2, а затем на 3 во время фиксации транзакции T2. Окончательный статус базы данных идентичен статусу выполнения каждой транзакции независимо, без какого-либо влияния на другие транзакции. Следовательно, он удовлетворяет свойству ACID. Этот метод называется контролем одновременного выполнения нескольких версий (MVCC).

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

В 2PL уровень изоляции транзакций контролирует следующее :

  • Принимаются ли блокировки при чтении данных и какой тип блокировки запрашивается.

  • Как долго удерживаются блокировки чтения.

  • Изменена ли операция чтения со ссылками на строки другой транзакцией:

    • Блокировать, пока исключительная блокировка строки не будет освобождена.

    • Получите зафиксированную версию строки, которая существовала на момент запуска оператора или транзакции.

    • Прочтите незафиксированную модификацию данных.

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

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

Конкретные примеры связи между блокировками и уровнями изоляции в SQL Server (используйте 2PL, кроме READ_COMMITED с READ_COMMITTED_SNAPSHOT = ON)

  • READ_UNCOMMITED: не применять разделяемые блокировки для предотвращения изменения данных, считываемых текущей транзакцией, другими транзакциями. READ UNCOMMITTED транзакции также не блокируются эксклюзивными блокировками, которые не позволят текущей транзакции читать строки, которые были изменены, но не зафиксированы другими транзакциями. [...]

  • READ_COMMITED:

    • Если READ_COMMITTED_SNAPSHOT установлен в OFF (по умолчанию): использует разделяемые блокировки, чтобы предотвратить изменение строк другими транзакциями, пока текущая транзакция выполняет операцию чтения. Совместно используемые блокировки также блокируют чтение оператором строк, измененных другими транзакциями, до тех пор, пока другая транзакция не будет завершена. [...] Блокировки строк снимаются до обработки следующей строки. [...]
    • Если READ_COMMITTED_SNAPSHOT имеет значение ON, компонент Database Engine использует управление версиями строк, чтобы представить каждому оператору согласованный с транзакционной точки зрения моментальный снимок данных в том виде, в каком он существовал в начале оператора. Блокировки не используются для защиты данных от обновлений другими транзакциями.
  • REPETEABLE_READ: общие блокировки устанавливаются на все данные, считываемые каждым оператором в транзакции, и удерживаются до завершения транзакции.

  • SERIALIZABLE: блокировки диапазона помещаются в диапазон значений ключа, который соответствует условиям поиска каждого оператора, выполняемого в транзакции. [...] Блокировки диапазона удерживаются до завершения транзакции.

Габриэльджусси
источник
5

Блокировки всегда принимаются на уровне БД: -

Официальный документ Oracle: - Чтобы избежать конфликтов во время транзакции, СУБД использует блокировки, механизмы для блокировки доступа других лиц к данным, к которым обращается транзакция. (Обратите внимание, что в режиме автоматической фиксации, где каждый оператор является транзакцией, блокировки удерживаются только для одного оператора.) После установки блокировки она остается в силе до тех пор, пока транзакция не будет зафиксирована или откат. Например, СУБД может заблокировать строку таблицы до тех пор, пока в ней не будут зафиксированы обновления. Эффект этой блокировки будет заключаться в том, чтобы не дать пользователю получить грязное чтение, то есть прочитать значение до того, как оно станет постоянным. (Доступ к обновленному значению, которое не было зафиксировано, считается «грязным» чтением, потому что это значение может быть откатано до его предыдущего значения. Если вы прочитаете значение, которое позже откатывается, вы прочитаете недопустимое значение. )

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

Одним из примеров уровня изоляции транзакции является TRANSACTION_READ_COMMITTED, который не позволит получить доступ к значению до тех пор, пока оно не будет зафиксировано. Другими словами, если уровень изоляции транзакции установлен на TRANSACTION_READ_COMMITTED, СУБД не допускает грязных чтений. Интерфейс Connection включает пять значений, которые представляют уровни изоляции транзакции, которые вы можете использовать в JDBC.

Гоял Вики
источник