• Главная
  • Публикации
  • Управление транзакциями. Типы транзакций. Типы блокировок. Управление блокировками: получение информации о процессах и блокируемых ресурсах. Команды создания, завершения, отката транзакции. Команды управления транзакциями.

Управление транзакциями. Типы транзакций. Типы блокировок. Управление блокировками: получение информации о процессах и блокируемых ресурсах. Команды создания, завершения, отката транзакции. Команды управления транзакциями.

Транзакцией называется совокупность команд языка SQL, результаты действия которых для базы данных представляют собой единое целое.

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

Простым примером может служить пример транзакции в банковской сфере, когда требуется некоторую сумму денег перевести с одного счета на другой. Если между операциями списывания денег с одного счета и зачисления денег на другой счет произойдет ошибка, то один из участников транзакции (владелец одного из счетов) окажется в незавидной ситуации, так как бессмысленно и только списание денег с одного счета, и только зачисления денег на другой счет.

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

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

Плоские (или традиционные) транзакции характеризуются четырьмя классическими свойствами: атомарности, согласованности, изолированности, долговечности (прочности). По-английски эти свойства называются Atomicity, Consistency, Isolation и Durability, сокращенно ACID. Поэтому традиционные транзакции иногда также называют ACID-транзакциями.

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

Свойство согласованности (Consistency) гарантирует, что по мере выполнения транзакций данные переходят из одного согласованного состояния в другое, то есть транзакция не разрушает взаимной согласованности данных.

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

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

Свойство изолированности заслуживает особого внимания. В идеальном варианте транзакции разных пользователей должны выполняться так, чтобы у пользователя создавалась иллюзия, что он один в системе. Простейший способ обеспечить абсолютную изолированность состоит в том, чтобы выстроить транзакции в очередь и выполнять их строго одну за другой. Однако, при этом теряется эффективность работы системы. Поэтому реально одновременно выполняется несколько транзакций (смесь транзакций), что может приводить к конфликтным ситуациями.

При параллельном использовании транзакций могут возникать следующие проблемы:

• неповторяющееся чтение (non-repeatable read);

• "грязное" чтение (dirty read) - чтение данных, которые были записаны откатанной транзакцией;

• потерянное обновление (lost update);

• фантомная вставка (phantom insert).

Рассмотрим каждую из ситуаций, в которых возможно возникновение данных проблем, подробнее.

Неповторяющееся чтение: возьмем две транзакции, которые были открыты различными приложениями, и в которых выполняются следующие SQL-операторы:

Транзакция 1 Транзакция 2

SELECT F2 FROM T1 WHERE F1=1; SELECT F2 FROM T1 WHERE F1=1;

UPDATE T1 SET F2=F2+1 WHERE F1=1;

SELECT F2 FROM T1 WHERE F1=1;

В транзакции 2 выбирается значение поля F2, после чего в транзакции 1 изменяется значение этого поля. Тогда при повторной попытке выбора значения из поля F2 в транзакции 2 будет получен другой результат. Эта ситуация особенно опасна в том случае, когда данные считываются с целью их частичного изменения и обратной записи в базу данных.

«Грязное» чтение: возьмем две транзакции, которые были открыты различными приложениями, и в которых выполняются следующие SQL-операторы:

Транзакция 1 Транзакция 2

SELECT F2 FROM T1 WHERE F1=1;

UPDATE T1 SET F2=F2+1 WHERE F1=1;

SELECT F2 FROM T1 WHERE F1=1;

ROLLBACK WORK;

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

Потерянное обновление: возьмем две транзакции, которые были открыты различными приложениями, и в которых выполняются следующие SQL-операторы:

Транзакция 1 Транзакция 2

SELECT F2 FROM T1 WHERE F1=1; SELECT F2 FROM T1 WHERE F1=1;

UPDATE T1 SET F2=20 WHERE F1=1;

UPDATE T1 SET F2=25 WHERE F1=1;

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

Фантомная вставка: возьмем две транзакции, которые были открыты различными приложениями, и в которых выполняются следующие SQL-операторы:

Транзакция 1 Транзакция 2

SELECT SUM(F2) FROM T1;

INSERT INTO T1 (F1, F2) VALUES (15, 20);

SELECT SUM(F2) FROM T1;

В транзакции 2 выполняется SQL-оператор, использующий все значения поля F2. Затем в транзакции 1 выполняется вставка новой строки, приводящая к тому, что повторное выполнение SQL-оператора в транзакции 2 выдаст другой результат. Такая ситуация называется фантомной вставкой и является частным случаем неповторяющегося чтения. При этом, если выполняемый SQL-оператор выбирает не все значения поля F2, а только значение одной строки таблицы (используется предикат WHERE), то выполнение оператора INSERT не приведет к ситуации фантомной вставки (если новая строка не будет удовлетворять условию фильтрации).

Для предотвращения возникновения описанных конфликтных ситуаций в стандарте SQL-92 определили уровни изоляции транзакций:

• SERIALIZABLE – последовательное выполнение транзакций (используется по умолчанию). Этот уровень гарантирует предотвращение всех описанных выше конфликтных ситуаций, но при нем наблюдается самая низкая степень параллелизма;

• REPEATABLE READ – повторяющееся чтение. На этом уровне разрешено выполнение операторов INSERT, приводящих к конфликтной ситуации «фантомная вставка». Этот уровень целесообразно использовать, если на выполняющиеся SQL-операторы не влияет добавление новых строк;

• READ COMMITED – фиксированное чтение. Этот уровень изоляции позволяет получать разные результаты для одинаковых запросов, но только после фиксации транзакции, повлекшей изменение данных;

• READ UNCOMMITED – нефиксированное чтение. Здесь возможно получение разных результатов для одинаковых запросов без учета фиксации транзакции.

Уровень изоляции Предотвращение конфликтной ситуации

неповторяющееся чтение (non-repeatable read) "грязное" чтение (dirty read) потерянное обновление (lost update) фантомная вставка (phantom insert)

SERIALIZABLE + + + +

REPEATABLE READ + + + -

READ COMMITED - + + -

READ UNCOMMITED - - + -

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

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

Выделяют два типа блокировок:

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

• монопольный режим блокировки – предполагает монопольный захват объекта и требуется для выполнения операция «записи» (добавление записей, удаление, модификация). Объекты, заблокированные таким образом, недоступны для других транзакций до момента завершения работы текущей транзакции.

Однако, помимо решения некоторых проблем использование блокировок добавило и несколько новых – блокирование (blocking) и взаимоблокировку (deadlock). Они могут замедлять и даже останавливать работу.

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

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

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

В языке SQL определен оператор явной блокировки таблицы LOCK TABLE. Его синтаксис следующий:

LOCK TABLE имя_таблицы IN { SHARED | EXCLUSIVE } MODE

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

Транзакции начинаются с выполнения первой исполняемой команды SQL и заканчиваются либо фиксацией транзакции (фиксацией изменений в базе данных), либо отказом от фиксации (откатом). Таким образом, окончанием транзакции может служить одно из следующих событий:

- команда COMMIT (фиксации транзакции) или ROLLBACK (откат);

- успешное завершение программы, инициировавшей текущую транзакцию (автоматическая фиксация);

- ошибочное завершение программы, инициировавшей текущую транзакцию (автоматический откат).

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

Состояние данных в базе до и после выполнения транзакции удовлетворяет определенным правилам.

До выполнения команды COMMIT или ROLLBACK:

- предыдущее состояние базы данных может быть восстановлено, так как изменения производятся не в самой базе, а в буфере базы данных;

- текущий пользователь может просмотреть результаты операций DML с помощью оператора SELECT;

- другие пользователи не могут видеть результаты команд DML, выполняемых текущим пользователем;

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

После выполнения команды COMMIT:

- измененные данные вносятся фактически в базу данных;

- предшествующее изменениям состояние теряется и не может быть восстановлено;

- все пользователи могут видеть результаты произведенных изменений;

- измененные строки в таблицах разблокируются, и другие пользователи получают к ним доступ;

- все точки сохранения стираются.

После выполнения команды ROLLBACK:

- все незавершенные изменения отменяются;

- фактически данные в базе данных возвращаются в прежнее состояние;

- отменяется блокировка строк, над которыми производились изменения.

Согласно определенной в стандарте ANSI/ISO SQL модели транзакций каждый оператор, который изменяет состояние базы данных, рассматривается как транзакция, поэтому при успешном завершении этого оператора база данных переходит в новое устойчивое состояние. В дальнейшем в СУБД SYBASE была предложена расширенная модель транзакций, включившая ряд дополнительным операций. В модели SYBASE используются следующие четыре оператора:

- BEGIN TRANSACTION – сообщает о начале транзакции, в отличие от модели ANSI/ISO в модели SYBASE начало транзакции задается явно с помощью оператора начала транзакции;

- COMMIT TRANSACTION – сообщает об успешном завершении транзакции, оператор эквивалентен COMMIT в модели ANSI/ISO, фиксирует все изменения, которые были произведены в базе данных в ходе выполнения транзакции;

- SAVE TRANSACTION – создает внутри транзакции точку сохранения, соответствующую промежуточному состоянию базы данных, сохраненному на момент выполнения оператора, оператор допускает использование имени точки сохранения, так что в ходе выполнения транзакции может быть сохранено несколько таких точек;

- ROLLBACK – используется в двух вариантах, без указания дополнительных параметров эквивалентен оператору ROLLBACK в модели ANSI/ISO, при использовании в качестве параметра имени точки сохранения частично откатывает транзакцию в указанное состояние.

Использование точки сохранения позволяет выполнять откат только до определенной точки в транзакции, а не до самого начала транзакции. Все модификации, выполненные до точки сохранения, остаются в силе и не подвергаются откату; но для всех операторов, выполняемых после точки сохранения (которую вы должны указать в транзакции) вплоть до оператора ROLLBACK, будет выполнен откат. Затем начнут выполняться операторы, следующие за оператором ROLLBACK.

Синтаксис оператора SAVE TRANSACTION следующий:

SAVE TRANSACTION {имя_точки_сохранения | @переменная_с_именем_точки_сохранения}

Например, создание точки сохранения может выполняться командой:

SAVE TRANSACTION save_point_2

После этого можно осуществить откат до данной точки сохранения следующей командой:

ROLLBACK save_point_2

Определение параметров транзакции выполняется оператором SET TRANSACTION, который имеет в стандарте SQL-92 следующий синтаксис:

SET TRANSACTION ISOLATION LEVEL [{SERIALIZABLE |

REPEATABLE READ |

READ COMMITED |

READ UNCOMMITED}] [{READ WRITE |

READ ONLY}]

Ключевое слово ISOLATION LEVEL позволяет установить желаемый уровень изоляции транзакций. По умолчанию предполагается уровень SERIALIZABLE. Если задан уровень READ COMMITED, то допустимы только операции чтения в транзакции, поэтому в этом случае нельзя установить операции READ WRITE.

Комментарии

Все комментарии
1комментарий

Ян ОПИ(Э) 07 27 октября, 2009 в 13:51:11

Осилил :D интересная лекция...

Добавить комментарий