В системах баз данных изоляция является одним из свойств транзакции ACID ( атомарность , согласованность , изоляция, долговечность ) . Она определяет, как целостность транзакции видна другим пользователям и системам. Более низкий уровень изоляции увеличивает возможность многих пользователей получать доступ к одним и тем же данным одновременно, но также увеличивает количество эффектов параллелизма (таких как грязное чтение или потерянные обновления ), с которыми могут столкнуться пользователи. И наоборот, более высокий уровень изоляции уменьшает типы эффектов параллелизма, с которыми могут столкнуться пользователи, но требует больше системных ресурсов и увеличивает вероятность того, что одна транзакция заблокирует другую. [1]
Управление параллелизмом включает в себя базовые механизмы в СУБД , которые обрабатывают изоляцию и гарантируют соответствующую корректность. Он активно используется базами данных и механизмами хранения как для гарантии правильного выполнения параллельных транзакций, так и (через различные механизмы) корректности других процессов СУБД. Механизмы, связанные с транзакциями, обычно ограничивают синхронизацию операций доступа к данным базы данных ( расписания транзакций ) определенными порядками, характеризуемыми как свойства сериализуемости и восстанавливаемости . Ограничение выполнения операций доступа к базе данных обычно означает снижение производительности (измеряемой скоростью выполнения), и, таким образом, механизмы управления параллелизмом обычно разрабатываются для обеспечения наилучшей производительности в условиях ограничений. Часто, когда это возможно без ущерба для корректности, свойство сериализуемости ставится под угрозу ради лучшей производительности. Однако восстанавливаемость не может быть поставлена под угрозу, поскольку это обычно приводит к нарушению целостности базы данных .
Двухфазная блокировка — наиболее распространенный метод управления параллелизмом транзакций в СУБД, используемый для обеспечения как сериализуемости, так и восстанавливаемости для корректности. Для доступа к объекту базы данных транзакция сначала должна получить блокировку для этого объекта. В зависимости от типа операции доступа (например, чтение или запись объекта) и типа блокировки получение блокировки может быть заблокировано и отложено, если другая транзакция удерживает блокировку для этого объекта.
Изоляция обычно обеспечивается на уровне базы данных. Однако также могут использоваться различные клиентские системы. Она может контролироваться в прикладных фреймворках или контейнерах времени выполнения, таких как J2EE Entity Beans [2] В старых системах она может быть реализована системно (разработчиками приложений), например, с помощью временных таблиц. [ неудачная проверка ] В двухуровневых, трехуровневых или n-уровневых веб-приложениях менеджер транзакций может использоваться для поддержания изоляции. Менеджер транзакций — это промежуточное программное обеспечение , которое находится между службой приложения (службой внутреннего приложения) и операционной системой. Менеджер транзакций может обеспечить глобальную изоляцию и атомарность. Он отслеживает, когда новые серверы присоединяются к транзакции, и координирует протокол атомарной фиксации между серверами. Детали абстрагируются от приложения, что упрощает транзакции и облегчает их кодирование. Монитор обработки транзакций (TPM) — это набор промежуточного программного обеспечения, включая менеджер транзакций. TPM может обеспечить локальную изоляцию для приложения с помощью менеджера блокировок. [2]
Стандарт ANSI/ISO SQL 92 описывает три различных феномена чтения , когда транзакция извлекает данные, которые могла обновить другая транзакция.
В следующих примерах выполняются две транзакции. В транзакции 1 выполняется запрос, затем в транзакции 2 выполняется обновление и, наконец, в транзакции 1 снова выполняется тот же запрос.
В примерах используется следующее соотношение:
Грязное чтение (также известное как незафиксированная зависимость ) происходит, когда транзакция извлекает строку, которая была обновлена другой транзакцией, которая еще не зафиксирована.
В этом примере транзакция 1 извлекает строку с идентификатором 1, затем транзакция 2 обновляет строку с идентификатором 1, и, наконец, транзакция 1 снова извлекает строку с идентификатором 1. Теперь, если транзакция 2 откатывает свое обновление (уже извлеченное транзакцией 1) или выполняет другие обновления, то представление строки в транзакции 1 может быть неверным. На уровне изоляции READ UNCOMMITTED второй SELECT в транзакции 1 извлекает обновленную строку: это грязное чтение. На уровнях изоляции READ COMMITTED, REPEATABLE READ и SERIALIZABLE второй SELECT в транзакции 1 извлекает начальную строку.
Неповторяющееся чтение происходит, когда транзакция извлекает строку дважды, и эта строка обновляется другой транзакцией, которая фиксируется между ними.
В этом примере транзакция 1 извлекает строку с идентификатором 1, затем транзакция 2 обновляет строку с идентификатором 1 и фиксируется, и, наконец, транзакция 1 снова извлекает строку с идентификатором 1. На уровнях изоляции READ UNCOMMITTED и READ COMMITTED второй SELECT в транзакции 1 извлекает обновленную строку: это неповторяемое чтение. На уровнях изоляции REPEATABLE READ и SERIALIZABLE второй SELECT в транзакции 1 извлекает начальную строку.
Фантомное чтение происходит, когда транзакция извлекает набор строк дважды, а новые строки вставляются в этот набор или удаляются из него другой транзакцией, которая фиксируется между ними.
В этом примере транзакция 1 извлекает набор строк с возрастом больше 17, затем транзакция 2 вставляет строку с возрастом 26 и фиксируется, и, наконец, транзакция 1 снова извлекает набор строк с возрастом больше 17. На уровнях изоляции READ UNCOMMITTED, READ COMMITTED и REPEATABLE READ второй SELECT в транзакции 1 извлекает новый набор строк, включающий вставленную строку: это фантомное чтение. На уровне изоляции SERIALIZABLE второй SELECT в транзакции 1 извлекает начальный набор строк.
Существуют две основные стратегии, используемые для предотвращения неповторяющихся чтений и фантомных чтений. В первой стратегии, управление параллелизмом на основе блокировок , транзакция 2 фиксируется после того, как транзакция 1 фиксируется или откатывается. Это создает последовательное расписание T1, T2 . В другой стратегии, управление параллелизмом на основе мультиверсий , транзакция 2 фиксируется немедленно, в то время как транзакция 1, которая началась до транзакции 2, продолжает работать со старым снимком базы данных, сделанным в начале транзакции 1, и когда транзакция 1 в конечном итоге пытается зафиксироваться, если результат фиксации будет эквивалентен последовательному расписанию T1, T2 , то транзакция 1 фиксируется; в противном случае возникает конфликт фиксации, и транзакция 1 откатывается с ошибкой сериализации.
При управлении параллелизмом на основе блокировок неповторяющиеся чтения и фантомные чтения могут возникать, когда блокировки чтения не получены при выполнении SELECT или когда полученные блокировки затронутых строк снимаются сразу после выполнения SELECT. При управлении параллелизмом с несколькими версиями неповторяющиеся чтения и фантомные чтения могут возникать, когда требование, чтобы транзакция, затронутая конфликтом фиксации, была откачена, смягчено.
Из четырех свойств ACID в СУБД (система управления базами данных) свойство изоляции является наиболее часто ослабляемым. При попытке поддержания наивысшего уровня изоляции СУБД обычно устанавливает блокировки на данные, что может привести к потере параллелизма , или реализует управление параллелизмом многоверсионности . Это требует добавления логики для корректной работы приложения .
Большинство СУБД предлагают ряд уровней изоляции транзакций , которые контролируют степень блокировки, возникающую при выборе данных. Для многих приложений баз данных большинство транзакций базы данных можно сконструировать так, чтобы избежать необходимости высоких уровней изоляции (например, уровня SERIALIZABLE), тем самым снижая накладные расходы на блокировку для системы. Программист должен тщательно проанализировать код доступа к базе данных, чтобы гарантировать, что любое ослабление изоляции не приведет к ошибкам программного обеспечения, которые трудно найти. И наоборот, если используются более высокие уровни изоляции, увеличивается вероятность взаимоблокировки , что также требует тщательного анализа и методов программирования, чтобы избежать.
Поскольку каждый уровень изоляции сильнее, чем нижележащие, то есть ни один из уровней изоляции выше не допускает действия, запрещенного уровнем ниже, стандарт разрешает СУБД выполнять транзакцию на уровне изоляции выше запрошенного (например, транзакция «Read commited» фактически может быть выполнена на уровне изоляции «Repeatable read»).
Уровни изоляции, определенные стандартом ANSI / ISO SQL, перечислены ниже.
Это наивысший уровень изоляции.
При реализации СУБД с управлением параллелизмом на основе блокировки сериализуемость требует снятия блокировок чтения и записи (приобретенных для выбранных данных) в конце транзакции. Также должны быть получены блокировки диапазона , когда запрос SELECT использует предложение WHERE с диапазоном , особенно для того, чтобы избежать феномена фантомных чтений .
При использовании управления параллелизмом без блокировки блокировки не устанавливаются; однако, если система обнаруживает конфликт записи между несколькими параллельными транзакциями, только одной из них разрешено зафиксироваться. Подробнее об этом см. в разделе «Изоляция моментального снимка» .
Из: (Второй неофициальный обзорный проект) ISO/IEC 9075:1992, Язык баз данных SQL - 30 июля 1992 г.: Выполнение параллельных SQL-транзакций на уровне изоляции SERIALIZABLE гарантированно является сериализуемым. Сериализуемое выполнение определяется как выполнение операций параллельного выполнения SQL-транзакций, которое производит тот же эффект, что и некоторое последовательное выполнение тех же самых SQL-транзакций. Последовательное выполнение - это выполнение, при котором каждая SQL-транзакция выполняется до завершения до начала следующей SQL-транзакции.
На этом уровне изоляции реализация СУБД управления параллелизмом на основе блокировки сохраняет блокировки чтения и записи (приобретенные на выбранных данных) до конца транзакции. Однако блокировки диапазонов не управляются, поэтому могут происходить фантомные чтения .
На этом уровне изоляции в некоторых системах возможен перекос записи. Перекос записи — это явление, когда двум разным писателям (которые ранее читали обновляемые ими столбцы) разрешается две записи в один и тот же столбец(ы) таблицы, в результате чего столбец содержит данные, которые являются смесью двух транзакций. [3] [4]
На этом уровне изоляции реализация СУБД с управлением параллелизмом на основе блокировки сохраняет блокировки записи (приобретенные на выбранных данных) до конца транзакции, но блокировки чтения снимаются, как только выполняется операция SELECT (поэтому на этом уровне изоляции может возникнуть явление неповторяющихся чтений ). Как и на предыдущем уровне, блокировки диапазона не управляются.
Проще говоря, read commited — это уровень изоляции, который гарантирует, что любое чтение данных фиксируется в момент чтения. Он просто ограничивает читателя от просмотра любого промежуточного, незафиксированного, «грязного» чтения. Он не дает никаких гарантий, что если транзакция повторно выдаст чтение, она найдет те же данные; данные могут свободно изменяться после чтения.
Это самый низкий уровень изоляции. На этом уровне разрешены грязные чтения , поэтому одна транзакция может видеть еще не зафиксированные изменения, внесенные другими транзакциями.
Уровень изоляции по умолчанию различных СУБД варьируется довольно широко. Большинство баз данных, в которых есть транзакции, позволяют пользователю устанавливать любой уровень изоляции. Некоторые СУБД также требуют дополнительного синтаксиса при выполнении оператора SELECT для получения блокировок (например, SELECT … FOR UPDATE для получения исключительных блокировок записи на доступных строках).
Однако приведенные выше определения подверглись критике как неоднозначные и неточно отражающие изоляцию, обеспечиваемую многими базами данных:
Существуют и другие критические замечания относительно определения изоляции ANSI SQL, поскольку оно поощряет разработчиков совершать «плохие вещи»:
Аномалия сериализуемая не то же самое, что сериализуемая. То есть, необходимо, но недостаточно, чтобы сериализуемое расписание было свободно от всех трех типов явлений. [5]
(см. выше примерно на 13:30 минуте веб-трансляции!)