Транзакции в базах данных
6.2 Языки управления транзакциями
Будем рассматривать так называемые плоские транзакции, обладающие одним управляющим слоем. Именно этот тип широко распространен в современных СУБД.
Существует два способа запуска транзакции:
- Транзакция начинается автоматически с момента присоединения пользователя к СУБД или по завершении предыдущей транзакции (например, в Oracle).
- Транзакция начинается специальной командой, например, BEGIN TRANSACTION или другой командой аналогичного назначения (например, в Cache).
Транзакция завершается, успешно или не успешно, специальными командами или по одному из событий:
- Команда COMMIT [WORK] (зафиксировать транзакцию).
- Команда ROLLBACK [WORK] (откатить транзакцию).
- Событие "Отключение пользователя от СУБД".
- Событие "Сбой системы".
- Событие "Отключение системы".
В языке COS начало транзакции — команда TSTART, успешное завершение — TCOMMIT, неуспешное — TROLLBACK.
В таблице 6.1 приведены команды управления данными для Cache.
Команда SQL | Команда COS | Описание |
%BEGTRANS | TSTART | Начало транзакции |
COMMIT [WORK] | TCOMMIT | Успешное завершение транзакции |
ROLLBACK [WORK] | TROLLBACK | Неуспешное завершение транзакции |
Замечание. В Oracle любые действия вкладываются в транзакции, в Cache транзакции используются по желанию пользователя. Пользователь Cache, работающий вне транзакции как бы "не замечает",
чужих транзакций.
Создадим и откомпилируем программу ^tr1 содержащую транзакцию:
SET ^tt(0)=0, ^tt(1)=1 ;значения до транзакции TSTART ;начало транзакции SET ^tt(0)= "Значение 1 из транзакции" READ x ;приостанавливает исполнение SET ^tt(1)= "Значение 2 из транзакции" TCOMMIT /* конец транзакции - успешное завершение */ WRITE "^tt(0)= ",^tt(0),!, "^tt(1)= ", ^tt(1) QUIT
Вы помните, что в Cache данные бестиповые, тип данных определяется по контексту. Например запись -x приведет к интерпретации x как числа. В программе ^tr1 назначаем глобалам ^tt(0) и ^tt(1) цифровые значения. А в транзакции присваиваем им текстовые значения. READ x используется для остановки исполнения программы за счет ожидания ввода данных человеком. В конце печатается текст ^tt(0) =.. ^tt(1) =.. и сами значения этих глобалов. Если транзакция откатывалась, то глобалам ^tt(0) и ^tt(1) возвращаются цифровые значения.
Запустим два терминала.
Просмотрим два варианта исполнения транзакции:
- С вводом пустого значения в переменную x (левый терминал) — см. рисунок ниже. Сначала в левом терминале исполняется программа ^tr1 , затем в правом читается значение глобала. Транзакция завершилась успешно, поэтому возвращены текстовые значения.
- С выключением левого терминала (для выключения нажмите на кнопку с крестиком
-см. рисунок ниже. Правый терминал читает ^tt(0) первый раз до выключения левого терминала, а второй раз — после его выключения. Вывод: выключение терминала откатывает транзакцию.
6.3 Транзакции и ограничения целостности
Переходим к первой задаче, которую решают транзакции — соблюдение ограничений целостности. Что нужно для проверки любого ограничения? Прежде всего, база должна быть активной, то есть иметь способность совершать что-то, сверх того, о чем ее попросили. Пусть задано ограничение первичный ключ. Когда мы приказываем ввести строку, СУБД сама обнаруживает, что такое ограничение имеется и запускает процедуру, проверяющую, не повторяются ли значения в ключевых столбцах. И, наверное, она не позволит ввести строку с повторяющимся значением ключа. Хорошо бы еще получить какое-то сообщение о возможном нарушении ограничения целостности.
Чаще всего источник активности — специальные процедуры, называемые триггерами. Но это не единственный вариант. Триггеры напоминают резидентные программы. Они начинают работать только при запуске некоторого процесса, называемого триггерным событием. В число таких событий всегда входят вставка, удаление и обновление строк (по-английски insert, update и delete). В современных базах данных триггеры могут реагировать и на другие события. Поскольку ограничения целостности определены для хранимых объектов базы, триггеры прикрепляются к этим объектам.
Рассмотрим ограничения целостности и реакции СУБД на их нарушения. Приведем примеры ограничений целостности, в том числе ссылочных. Изучим классификацию ограничений целостности по способам реализации, по времени проверки и по области действия. В частности, уточним, что такое триггеры.
6.3.1 Нарушения целостности
Определение. База данных находится в согласованном (целостном) состоянии, если выполнены все заданные в ней ограничения целостности.
Для распределенных баз данных важна еще согласованность копий фрагментов данных в узлах. Меру различия между копиями данных в узлах сети (репликами) называют связностью данных. Распределенная база не может обеспечить одновременно высокую связность и высокую скорость работы. Чем выше связность, тем больше трафик по сети и тем выше загрузка серверов, реплицирующих данные.
Система управления базами данных обязана реагировать на любые попытки нарушения целостности.
Два основных типа реакции СУБД:
- Отказ выполнить "недопустимую" операцию.
- Выполнение действий, компенсирующих нарушения ограничений целостности. Далее мы поясним этот тип на примере.
Классификация ограничений целостности проводится по следующим основаниям:
- По способам реализации.
- По времени проверки.
- По области действия.
6.3.2 Классификация по способам реализации
Различают
- декларативную поддержку ограничений целостности;
- процедурную поддержку ограничений целостности.
Декларативная поддержка ограничений целостности задается средствами языка определения данных (ЯОД, он же DDL — Data Definition Language).
Приведем пример для языка SQL, который мы еще не изучали. Но это нам не сильно помешает. Создаем таблицу, используя следующую инструкцию:
CREATE TABLE person (persid INTEGER PRIMARY KEY, persname CHAR(30) NOT NULL);
Если прочитать ее на русском языке, все станет понятно. Итак: "СОЗДАТЬ ТАБЛИЦУ с названием person, содержащую два столбца: persid типа ЦЕЛОЕ с ограничением ПЕРВИЧНЫЙ КЛЮЧ и persname типа СИМВОЛЬНОЕ с длиной 30 символов и ограничением НЕЛЬЗЯ НЕ ЗАПОЛНЯТЬ".
Процедурная поддержка ограничений целостности
Процедурные ограничения целостности реализуются использованием триггеров и хранимых процедур.
Пример ограничения целостности, которое обычно реализуется процедурно: "Начальник отдела может изменять заработную плату только своим подчиненным и только в сторону уменьшения". Для того, чтобы реализовать это ограничение декларативно необходимо задать формулу, позволяющую найти строки для всех подчиненных и как-то указать, что будущие значения зарплат не больше уже существующих. Этого сделать нельзя, так как в базе нет этих будущих значений.
Деление на процедурные и декларативные ограничения целостности это не дихотомия, так как оба вида ограничений в действительности поддерживаются специальными процедурами. Просто в каждой СУБД определен список имен ограничений, которые можно записать декларативно. Остальные ограничения, для которых нет таких имен, реализуются явным заданием в процедурной части приложения.
Триггеры
Триггеры — это процедуры специального вида, прикрепленные к объекту базы, например, таблице, и срабатывающие при наступлении событий из некоторого набора событий. Наиболее известны триггеры, реализуемые в языке SQL.
В набор событий обычно входят вставка записи (инструкция INSERT в SQL), удаление записи (инструкция DELETE) и обновление записи (инструкция UPDATE).
Триггер может выполняться до отработки события (триггер BEFORE) и после его отработки (триггер AFTER).
Выделяют также триггеры уровня строки (записи), срабатывающие один раз на каждую выбранную строку, и триггеры уровня выражения, срабатывающие один раз при обработке набора записей (например, при входе в таблицу или выходе из нее). Итого 3 * 2 * 2 = 12 типов триггеров на один набор записей (таблицу).
Для проверки ограничения на возраст принимаемого на работу создают триггер на команду INSERT, срабатывающий до ее выполнения (нельзя допускать запись о неправильном приеме — значит выбираемый тип — BEFORE). В теле триггера вычисляют возраст, проверяют условие . Если условие не выполнено, запись о приеме аннулируется (рисунок 6.5).
Ссылочные ограничения целостности
Рассмотрим пример ссылочного ограничения целостности.
Пусть задана схема, состоящая из двух таблиц dept (отделы) и person (сотрудники) (таблицы 6.2 и 6.3).
Столбцы таблицы dept (deptid, deptname, deptquan): deptid — идентификатор подразделения, deptname —имя подразделения, deptquan — количество сотрудников в подразделении.
Столбцы таблицы person(persid, persname,deptid): persid — идентификатор сотрудника, persname —имя сотрудника, deptid —идентификатор подразделения, в котором работает сотрудник.
PERSID | PERSNAME | DEPTID |
1 | Иванов | 1 |
2 | Петров | 2 |
3 | Сидоров | 1 |
4 | Злобис | 2 |
5 | Вредис | 1 |
Имеющееся здесь ограничение ссылочной целостности определяется условием: поле deptquan должно содержать количество сотрудников, записанных в таблице person для каждого отдела.
Если уволим Иванова, недостаточно просто его вычеркнуть, потому что при этом изменится численность первого отдела. Ее нужно пересчитать, вычтя единицу из значения в столбце deptquan. А если переведем Иванова в транспортный цех, то необходимо не только изменить строку с Ивановым в таблице dept, но еще и прибавить к численности транспортного цеха единицу, вычтя единицу из численности цеха розлива. Иначе таблица "Отделы" окажется неправильно заполненной.
При наличии ссылочного ограничения, изменение в одной таблице обязательно влечет за собой изменение в другой таблице, причем изменение по вставке одно, по удалению другое, по изменению третье.
Например, прием нового сотрудника не может быть выполнен одной операцией. Необходимо вставить запись в таблицу person и одновременно увеличить значение поля deptquan на 1. Выполняем два шага, которые, конечно же, необходимо включить в транзакцию:
-
Вставить запись о сотруднике в таблицу person
INSERT INTO person VALUES (6, 'Петросян', 1).
(ВСТАВИТЬ в person строку (6, "Петросян", 1).)
-
Увеличить значение поля deptquan
UPDATE dept SET depquan=deptquan+l WHERE deptid=l.
(ОБНОВИТЬ dept, УСТАНОВИВ ЗНАЧЕНИЕ deptquan = deptquan+1 ДЛЯ СТРОКИ В КОТОРОЙ deptid= 1). Для увольнения и перемещения сотрудников необходимы свои транзакции.
Замечание. Пока мы не изучили инструкции SELECT, INSERT и UPDATE языка SQL, воспринимайте их просто как фразы, написанные на фрагменте естественного (как бы английского) языка, который понимает СУБД.
Примеры ограничений целостности
Пример 1. Возраст сотрудника не может быть меньше 21 и больше 45 лет (Декларативное ограничение типа check).
Пример 2. Атрибут "Табельный номер" уникален. (Декларативное ограничение—уникальный или первичный ключ).
Пример 3. Сотрудник обязан числиться в одном из отделов. (Декларативное ссылочное ограничение целостности).
Пример 4. Сумма накладной равняется сумме произведений цен товаров на количество товаров для всех товаров, входящих в накладную. (Определение вычислимого столбца.).
Замечание. Ограничение целостности может определять не только значения атрибутов, но и особенности удаления или обновления данных. Например, в схеме "Отдел" — "Сотрудник" удаление отдела может вызвать удаление его сотрудников или их перевод в другие отделы.
Задание ограничения целостности приходит в базу из бизнес-модели. Для проверки правильности этого перехода полезно определить, какие требования предлагает бизнесу это ограничение, то есть выполнить обратный переход. Например, задана уникальность табельного номера. Что это означает для бизнеса? Какой номер присваивается работнику при повторном приеме? Существуют ли сотрудники, не имеющие номера?
6.3.3 Классификация ограничений целостности по времени проверки
По времени проверки выделяют два вида ограничений:
- Немедленно проверяемые ограничения. Проверяются непосредственно в момент выполнения операции, могущей нарушить ограничение.
- Ограничения с отложенной проверкой. Проверяются в момент фиксации транзакции оператором COMMIT.
Пример немедленно проверямого ограничения — первичный ключ. Пример ограничения с отложенной проверкой — ссылочные ограничения (таблицы 6.2 и 6.3).
6.3.4 Классификация ограничений целостности по области действия
- Ограничения домена (из-за отсутствия в СУБД поддержки доменов такие ограничения обычно переносятся на атрибуты).
- Ограничения атрибута (немедленно проверяемые ограничения на допустимые значения атрибута). Реализуются почти всегда декларативно. Проверяют обычно попадание в диапазон или в список. Проверки на соответствие шаблону, например, в записи телефонного номера, в настоящее время реализуются с помощью регулярных выражений, то есть вне основной модели данных.
- Ограничения кортежа. Это ограничения на соотношение атрибутов одного экземпляра сущности.
- Ограничения отношения (или сущности или таблицы). Для проверки ограничения необходимо обработать все кортежи отношения. Пример: Только у двух человек в организации заработная плата может быть больше 100000.
- Ограничения на допустимые связи.
- Ограничения базы или схемы данных (межтабличные). Накладываются на свойства двух или более связанных между собой отношений. Пример: ссылочная целостность.
Итоговая классификация ограничений целостности приведена в разделе 6.6.
Ограничения на допустимые связи
Ограничения на допустимые связи могут определяться самими связываемыми сущностями. Но может понадобится учесть еще и другие сущности, как-то связанные с проверяемыми сущностями и не связанные напрямую проверяемой зависимостью.
В типичном случае имеется несколько взаимно исключающих связей. Например, сущность A может быть связана бинарной связью с B или C, но если существует связь A с B, то не может существовать связь A с C, и наоборот.
Возможно, наличие или отсутствие связи определяется состоянием экземпляров сущностей, которые могут входить в связь. Под состоянием здесь понимаются значения атрибутов сущностей, имеющих смысл "состояние".
Заметим, что реализация рассматриваемого класса ограничений достаточно сложна.
Одна из возможных связей — наследование. Реализация ограничений на наследование будет рассмотрена позже при изучении объектных моделей.