Чем выполняются триггеры базы данных
SQL-Ex blog
Новости сайта «Упражнения SQL», статьи и переводы
Руководство по триггерам в SQL: настройка отслеживания базы данных в PostgreSQL
Триггеры в SQL встречаются не так часто, однако они могут оказаться отличным решением в определенных ситуациях. Я покажу, как использовать триггеры в PostrgeSQL для обеспечения целостности данных и отслеживания изменений в базе.
В мире стартапов с открытыми исходными кодами и разработкой полного стека (типа Django, Rails, Javascript, PHP, MySQL, Postgres. ) очень популярны ORM, а средства типа триггеров SQL не так востребованы.
Но все же триггеры SQL сохраняют свое значение. Когда я работал над нестандартной ERP-системой, триггеры оказались неоценимым инструментом. При построении сильно ориентированного на данные ПО, особенно с данными в финансовой сфере, где точность является главным требованием, вы с большей вероятностью увидите, что данные обрабатываются непосредственно на более низком уровне.
В этой статье я поделюсь информацией о том, как эффективно использовать триггеры SQL.
Содержание
Что такое триггер?
Триггеры SQL, также называемые триггерами баз данных, позволяют вам сказать движку SQL (например PostgreSQL) выполнить часть кода при наступлении некоторого события, или даже перед наступлением события.
В PostgreSQL вы описываете исполняемый код посредством создания функции, которая возвращает значение типа trigger. В некоторых других движках, например, MySQL блок кода является частью триггера, и находится внутри него.
Прежде чем рассматривать различные типы событий и конкретный синтаксис создания триггера, обсудим, зачем бы вам понадобилось использовать триггеры баз данных.
Преимущества использования триггеров SQL
Поддержание целостности данных
Триггеры баз данных могут найти множество применений и являются прекрасным инструментом для обеспечения строгой целостности данных. Альтернативные решения типа хуков модели Django могут сбоить, если вы имеете другие серверы приложений или пользователей с доступом к базе данных, которые не знают конкретной бизнес-логики, закодированной в вашем приложении.
Разделение бизнес-логики
Размещение критичной бизнес-логики в коде приложения также представляет проблему, когда бизнес-логика обновляется. Если вашим бизнес-требованием являлось умножение входящих номеров на 10, а теперь вы захотели умножать это число на 20, изменение логики в SQL гарантировало бы, что каждые данные, начиная точно с момента развертывания, будут обрабатываться новой логикой.
Сервер SQL действует как единственная точка истины. Если логика внедрена на множестве серверов приложений, вы не сможете ожидать определенного изменения в поведении, выполненного чисто.
Атомарные транзакции
Естественная атомарность является еще одной желательной особенностью, присущей триггерам. Поскольку событие и триггерная функция являются частью одной атомарной транзакции, вы знаете с абсолютной определенностью, что триггер сработает, если возникнет событие. Они как единое целое в идеальном браке SQL.
Как создать триггер SQL: синтаксис PostgreSQL
Типы событий триггера
Триггеры баз данных будут мониторить конкретные события для таблицы. Вот некоторые примеры различных событий, которые могут активировать триггер:
Триггер базы данных допускает также перечисление более одного из этих событий.
Если одним из перечисленных событий является UPDATE, вы можете передать список столбцов, которые должны активировать триггер. Если вы не включаете этот список, обновление любого столбца будет его активировать.
Триггер BEFORE (до) или AFTER (после)
Триггер может выполняться либо до, либо после события.
Воздействие триггера
Триггер может выполняться либо на строку, либо на оператор. Скажем, вы выполняете один оператор UPDATE, который изменяет 5 строк в таблице.
Если вы укажете в триггере FOR EACH ROW, тогда триггер выполнится 5 раз. Если вы укажете FOR EACH STATEMENT, тогда он выполнится только раз.
И, конечно, мы не можем забыть о фактическом коде, который выполняется при срабатывании триггера. В PostgreSQL он помещается в функцию и отделен от триггера. Разделение триггера и кода, который он выполняет, создает более чистый код и позволяет нескольким триггерам выполнять один и тот же код.
Пример триггера #1: создание таймера
Фиксация времени прихода и ухода с работы сотрудников, и вычисление общего отработанного времени. Давайте создадим пример таймера и посмотрим, каким образом мы можем использовать триггеры для предотвращения ввода сотрудниками неверных данных.
Настройка схемы базы данных
В следующей статье я глубже погружусь в разработку схемы базы данных.
Для нашего примера я уже разработал схему таблиц. Нижеприведенный код создает таблицы employee и time_punch и вставляет некоторые данные по времени прохода для нового сотрудника Bear.
Bear зашел в 10:00 и вышел в 11:30 (длинный рабочий день). Давайте напишем запрос SQL для вычисления рабочего времени Bear.
Остановитесь и подумайте, как бы вы решили эту задачу при данной схеме и с помощью одного SQL.
Использование SQL для вычисления рабочего времени
Решение, которое я предлагаю, ищет на каждый «выход» соответствующий ему «вход».
В этом запросе я выбираю все выходы, затем я соединяю их с наиболее близким «входом». Беру разность временных меток и получаю количество часов, которое отработал Bear в каждой смене!
Пример триггера INSERT BEFORE: сохранение целостности данных
Нам требуется то, что не позволит нарушить шаблон вход/выход. К сожалению, ограничения check только отслеживают вставляемую или обновляемую строку и не могут учитывать данные из других строк.
Это идеальная ситуация для использования триггера баз данных!
Давайте создадим триггер для предотвращения события INSERT, которое нарушает наш шаблон. Сначала мы создадим «триггерную функцию». Эта функция есть то, что будет выполнять триггер при наступлении события.
Триггерная функция создается как обычная функция PostgreSQL за тем исключением, что возвращает триггер.
Ключевое слово new представляет значения вставляемой строки. Это также объект, который вы можете вернуть, чтобы позволить продолжиться вставке. Напротив, возвращение null остановит вставку.
Этот запрос сначала находит в time_punch предыдущее значение и гарантирует, что это значение входа/выхода не совпадает с вставляемым значением. Если значения совпадают, то триггер возвращает null, и time_punch не записывается. В противном случае, триггер возвращает new и оператор insert продолжается.
Теперь мы привяжем функцию в качестве триггера к таблице time_punch. BEFORE здесь ключевой момент. Если мы выполним этот триггер как триггер AFTER, он будет выполнен слишком поздно, чтобы остановить вставку.
Давайте попробуем вставить еще один «выход»:
Как можно видеть по выводу, триггер предотвратил вставку двух последовательных выходов для одного и того же сотрудника.
Можно также вызвать исключение из триггера с тем, чтобы ваше приложение (или лицо, выполняющее запрос SQL) получило уведомление об отказе вместо 0 как числа вставленных строк.
Пример триггера в PostgreSQL #2: создание таблицы аудита
Аккуратное сохранение данных о нахождении сотрудников критично для бизнеса. Данные подобного типа часто непосредственно отражаются на зарплате и, с другой стороны, на заработках компании.
Ввиду важности этих данных, пусть компания хочет воссоздавать в хронологии состояние таблицы на случай обнаружения нарушений.
Таблица аудита выполняет эту роль, отслеживая каждое изменение основной таблицы. Когда в главной таблице обновляется строка, в таблицу аудита вставляется строка в ее предыдущем состоянии.
Я буду использовать нашу таблицу time_punch для демонстрации создания и автоматического обновления таблицы аудита с помощью триггеров.
Создание таблицы аудита
После того, как произойдет обновление таблицы time_punch, выполнится этот триггер и запишет OLD (старое) значение времени прохода в нашу таблицу аудита.
Функция NOW() возвращает текущую дату и время с точки зрения сервера SQL. Если бы это было привязано к настоящему приложению, вы, вероятно, захотели бы передавать точное время, когда пользователь фактически сделал запрос, чтобы избежать расхождения из-за задержки.
Для триггера на обновление объект NEW представляет те значения, которые будут содержаться
в строке при успешном обновлении. Вы можете использовать триггер для «перехвата» вставки или обновления простым присвоением своих собственных значений в объект NEW. Объект OLD содержит значения строки до обновления.
Проверим, работает ли это! Я добавил второго пользователя с именем Daniel, который будет редактором времени прохода Bear.
Я собираюсь выполнить дважды нижеприведенный запрос для имитации 2 редакций, которые увеличивают время на 5 минут.
А вот таблица аудита, отражающая прошлые времена прохода:
Дополнительные сообщажения относительно триггеров
Обслуживание триггеров с течением времени
Бизнес-логика в коде приложения документируется естественным образом, т.к. она меняется со временем, с помощью git или другой системы управления исходниками. Разработчику легко увидеть логику в базовом коде и сделать быструю журнализацию git, а также посмотреть список изменений.
Обслуживание изменений со временем с помощью триггеров SQL и функций более сложно, менее стандартизовано и требует большего осмысливания и планирования.
Связанная логика триггера
Триггеры также могут запускать другие триггеры, быстро усложняя результаты казалось бы невинных INSERT или UPDATE. Этот риск также может привести к побочным эффектам кода приложения.
Опыт разработчиков
Знания триггеров так же довольно низки в среде некоторых разработчиков, поэтому введение их увеличивает вложения в обучение, которое потребуется новым разработчикам для успешной работы над проектом.
Изначально SQL может показаться неуклюжим и неудобным языком для изучения, поскольку многие из шаблонов, которые вы изучаете для построения запроса, «вывернуты наизнанку» по сравнению с тем, как вы извлекаете данные на процедурном языке.
Я надеюсь, что у вас появится возможность изучить и реализовать одну из самых увлекательных и интригующих функций SQL!
Обратные ссылки
Нет обратных ссылок
Комментарии
Показывать комментарии Как список | Древовидной структурой
Автор не разрешил комментировать эту запись
Триггер (базы данных)
Более простое определение триггера звучит так следующим образом.
Триггер — это хранимая процедура, которая не вызывается непосредственно, а исполняется при наступлении определенного события ( вставка, удаление, обновление строки ).
Триггеры применяются для обеспечения целостности данных и реализации сложной бизнес-логики. Триггер запускается сервером автоматически при попытке изменения данных в таблице, с которой он связан. Все производимые им модификации данных рассматриваются как выполняемые в транзакции, в которой выполнено действие, вызвавшее срабатывание триггера. Соответственно, в случае обнаружения ошибки или нарушения целостности данных может произойти откат этой транзакции.
Момент запуска триггера определяется с помощью ключевых слов BEFORE (триггер запускается до выполнения связанного с ним события; например, до добавления записи) или AFTER (после события). В случае, если триггер вызывается до события, он может внести изменения в модифицируемую событием запись (конечно, при условии, что событие — не удаление записи). Некоторые СУБД накладывают ограничения на операторы, которые могут быть использованы в триггере (например, может быть запрещено вносить изменения в таблицу, на которой «висит» триггер, и т. п.)
Кроме того, триггеры могут быть привязаны не к таблице, а к представлению (VIEW). В этом случае с их помощью реализуется механизм «обновляемого представления». В этом случае ключевые слова BEFORE и AFTER влияют лишь на последовательность вызова триггеров, так как собственно событие (удаление, вставка или обновление) не происходит.
В некоторых серверах триггеры могут вызываться не для каждой модифицируемой записи, а один раз на изменение таблицы. Такие триггеры называются табличными.
Содержание
SQL синтаксис определения триггеров
Полный синтаксис выглядит так:
Естественно, в языке имеется и конструкция, отменяющая определение триггера:
DROP TRIGGER trigger_name. (Конструкция ALTER TRIGGER в языке SQL не поддерживается.)
Синтаксические правила допускают несколько разновидностей определения триггера. Кратко обсудим эти разновидности.
Триггеры BEFORE и AFTER
Триггеры INSERT, UPDATE и DELETE
Заметим, что в стандарте SQL:1999 отсутствует возможность определения триггеров, для которых событием было бы выполнение операции выборки из предметной таблицы. Разработчики стандарта сочли, что область применения триггеров такого рода чересчур узка (трудно придумать какое-либо применение, кроме как для журнализации и аудита).
Триггеры ROW и STATEMENT
Раздел WHEN
Тело триггера
Простой синтаксис создания триггера
Примеры
В этом случае для отличия табличных триггеров от строчных вводится дополнительные ключевые слова при описании строчных триггеров. В Oracle это словосочетание FOR EACH ROW.
Подробнее о триггерах
История появления триггеров
Термин триггер в контексте реляционных баз данных был введен в обиход участниками проекта System R. В терминологии этого проекта триггером называлась хранимая в базе данных процедура, автоматически вызываемая СУБД при возникновении соответствующих условий. При определении триггера указывались два условия его применимости – общее условие (имя отношения и тип операции манипулирования данными) и конкретное условие (логическое выражение, построенное по правилам, близким к правилам ограничений целостности), а также действие, которое должно быть выполнено над БД при наличии условий применимости.
Конечно, термин триггер в данном контексте является жаргонным. Но, с другой стороны, он достаточно точно соответствует ситуации: для применения процедуры должны быть произведены «возбуждающие» ее действия. Как отмечалось в лекции 15, после завершения проекта System R на протяжении более десяти лет триггеры не поддерживались ни в одной коммерческой SQL-ориентированной СУБД. Но затем практически во всех ведущих СУБД механизм триггеров в том или ином виде был реализован.
В стандарте же языка SQL спецификации триггеров отсутствовали до принятия стандарта SQL:1999. По словам главного редактора стандартов SQL/92 и SQL:1999 Джима Мелтона, эта спецификация была уже полностью готова к моменту принятия SQL/92 и не вошла в текст стандарта только по причине ограниченности его объема. Однако, как мне кажется, этому препятствовали и расхождения в подходах, существовавшие между основными компаниями-производителями СУБД.
Заметим, что альтернативным термином по отношению к базам данных, содержащим триггерные процедуры, является термин активная база данных. Наверное, этот термин более точен, поскольку действительно речь идет о базах данных, содержащих процедуры, которые автоматически вызываются при срабатывании связанных с ними правил. Однако в обиходе пользователей SQL-ориентированных СУБД по-прежнему более распространен термин триггер.
Понятие триггера в SQL:1999
Триггерымогут срабатывать после и до реального выполнения инициирующего оператора SQL. В теле триггера допускается доступ к значениям вставляемых, модифицируемых и удаляемых строк. В случае операции модификации возможен доступ к значениям строк до модификации и к значениям после модификации. В соответствии со стандартом SQL:1999 любой триггер ассоциируется только с одной базовой таблицей. Не допускается определение триггеров над представлениями.
Можно придумать различные способы полезного применения механизма триггеров, но принято считать, что основными областями использования этого механизма являются следующие.
На практике при определении триггеров в качестве SQL_procedure_statement чаще всего используются операторы SQL обновления базы данных. Иногда (и мы покажем это на примере) для корректного определения функциональности триггера одного оператора не хватает, а в SQL отсутствует возможность определения составных операторов. Поэтому допускается использование средств определения составных операторов, присутствующих в SQL/PSM ( BEGIN ATOMIC и END ).
Введение в триггеры MySQL
Очень может быть, что вы знаете, что такое триггер базы данных, хотя бы в общих терминах. Есть даже шанс, что вы знаете, что MySQL поддерживает триггеры и имеет практику работы с ними. Но скорее всего, что большинство из вас, даже вооруженные знаниями не представляют себе, какие преимущества скрывают триггеры MySQL. Этот инструмент должен быть у вас на вооружении, так как триггеры могут полностью изменить ваш способ работы с данными.
Введение : что такое триггер
“Не смотря на то, что приложения становятся все более и более сложными, мы можем абстрагировать уровень приложений для того, чтобы управлять ими и увеличивать удобство процесса разработки.”
Триггеры были введены в MySQL начиная с версии 5.0.2. Синтаксис триггеров несколько чужероден. MySQL использует стандарт ANSI SQL:2003 для процедур и других функций. Если вы работаете с языками программирования, то понять его будет не сложно. Спецификация отсутствует в свободном доступе, поэтому мы постараемся использовать простые структуры и будем объяснять, что происходит в триггере. Будут использоваться такие же структуры, как и в любом языке программирования.
Как уже упоминалось выше, триггеры выполняются как процедуры при событиях UPDATE, DELETE и INSERT. Они могут быть выполнены либо до либо после определения события. Таким образом Вы можете определить триггер, которые будет выполняться перед DELETE или после DELETE, и так далее. Это значит, что можно иметь один триггер, который выполнится до INSERT и совершенно другой, который выполнится после INSERT, что является весьма мощным инструментом.
Начало: структура таблиц, инструменты и заметки
В статье мы будем работать с выдуманной системой для корзины покупок, каждый элемент которой будет иметь цену. Структура данных будет проста, насколько это возможно с целью продемонстрировать процедуры работы с триггерами. Наименования таблиц и столбцов придуманы с целью облегчения понимания, а не для реальной работы. Также используется TIMESTAMPS для облегчения учебного процесса. Таблицы имеют имена carts, cart_items, cart_log, items, items_cost.
Также будут использоваться очень простые запросы. Нет связи между переменными и не используется никакого ввода данных. Запросы подготавливались так, чтобы быть как можно более простыми и понятными для чтения.
Для определения времени выполнения использовался Particle Tree PHP Quick Profiler. Для иллюстрации эффектов на базе данных использовался Chive. Chive предназначен только для MySQL 5+ и очень похож на PHPMyAdmin. Он имеет более выразительный интерфейс, но содержит значительно больше ошибок на текущий момент. Использование Chive обусловлено желанием представить более выразительные скрин шоты запросов.
Чтобы изменить разделитель, нужно выполнить команду перед командой триггера:
А после команды триггера надо ввести:
Простой триггер : целостность данных
Если Вы захотите выполнить даже незначительную нормализацию структуры базы данных, может получиться так, что нужно будет удалять источник основных данных, который имеет фрагменты, участвующие в общем потоке данных. Например, у вас может быть cart_id, который ссылается на две или три таблицы без внешних ключей, особенно при использовании механизма MyISAM, который их не поддерживает.
Для такого случая раньше вы возможно выполняли следующие операции:
Вернемся к триггерам. Создадим простой триггер, который при удалении корзины будет удалять все элементы корзины, которые имеют такой же cart_id:
Очень простой синтаксис. Давайте разберем триггер подробно.
Первая строка“CREATE TRIGGER `tutorial`.`before_delete_carts`”. Это команда для MySQL создать триггер для базы данных “tutorial”, который будет иметь имя “before_delete_carts”. Будем использовать схему имен для триггеров “Когда_Что_Таблица”.
Вторая строка указывает для MySQL определение триггера “BEFORE DELETE ON `trigger_carts` FOR EACH ROW”. Мы говорим MySQL, что перед тем, как провести удаление из данной таблицы, для каждой строки нужно сделать что-то. Что нужно сделать, объясняется далее между BEGIN и END. “DELETE FROM trigger_cart_items WHERE OLD.cart_id = cart_id;” Для MySQL задается, что перед тем, как удалить из trigger_carts, нужно взять OLD.cart_id и также удалить из trigger_cart_items. Синтаксис OLD определяет переменную. Он будет обсуждаться в следующем разделе, где будут комбинироваться OLD и NEW.
Один запрос с триггером:
Как вы можете видеть, существует небольшой прирост производительности, которого следовало ожидать. База данных для примера использует тот же самый сервер, что и клиент. Но если сервер баз данных расположен в другом месте, то следует ожидать более значительной разницы, так как ко времени выполнения запросов добавится время передачи данных между серверами.Также нужно отметить, что первый раз триггер может выполняться значительно медленнее, чем в следующие разы.
Перемещение логики данных на уровень данных подобно тому, как задание стиля перемещается с уровня разметки на уровень презентации, что известно всему миру как CSS.
Чудесный простой триггер : журналирование и аудит
Следующий пример, который мы рассмотрим связан с журналированием событий. Например, мы хотим наблюдать за каждым товаром, который помещается в корзину. Возможно, мы хотим отслеживать рейтинг покупки товаров. Возможно, мы просто хотим иметь копию каждого товара, помещенного в корзину, не обязательно для продажи, а для анализа поведения покупателей. Какими бы ни были причины, давайте посмотрим на триггер INSERT, который открывает возможности для журналирования или аудита наших данных.
До использования триггера, вероятно мы делали что-то похожее:
Теперь мы можем создать очень простой триггер для процесса журналирования:
Первая строка “CREATE TRIGGER `after_insert_cart_items`”. Для MySQL задается команда, создать триггер с именем “after_insert_cart_items”. Имя может быть “Foo”, или “BullWinkle” или какое-то другое, но лучше использовать ранее описанную схему имен триггера. Далее следует “AFTER INSERT ON `trigger_cart_items` FOR EACH ROW”. Снова мы говорим, что после того, как что-то будет вставлено в trigger_cart_items, для каждой строки нужно выполнить операции между BEGIN и END.
Строка “INSERT INTO trigger_cart_log (cart_id, item_id) VALUES (NEW.cart_id, NEW.item_id);” является стандартным запросом с использованием двух переменных. Здесь используются значения NEW, которые вставляются в таблицу cart_items.
Снова выполнение нашего запроса осуществляется быстрее:
Для проверки, что триггер работает, посмотрим значения в таблице:
Более сложный триггер : бизнес логика
Начиная с этого момента мы перестанем рассматривать старый способ использования множественных запросов и их сравнение с техникой использования триггеров. Давайте рассмотрим несколько более продвинутых примеров использования триггеров.
Данный триггер работает отлично.
Для того, чтобы решить задачу, мы снова будем работать с UPDATE, но в этот раз триггер будет выполняться до выполнения запроса. Также будет использоваться выражение IF.
Вот текст триггера:
Заключение
В данной статье мы только слегка задели айсберг триггеров в MySQL. Они позволяют переносить правила работы с данными с уровня логики приложения на уровень данных.
Может быть, использование триггеров на одностраничном сайте и является суетой, которая отнимает время и силы. Но сложные вэб приложения могут совершенно преобразиться при использовании триггеров.
Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: www.net.tutsplus.com
Перевел: Сергей Фастунов
Урок создан: 4 Июля 2010
Просмотров: 147283
Правила перепечатки
5 последних уроков рубрики «Разное»
Как выбрать хороший хостинг для своего сайта?
Выбрать хороший хостинг для своего сайта достаточно сложная задача. Особенно сейчас, когда на рынке услуг хостинга действует несколько сотен игроков с очень привлекательными предложениями. Хорошим вариантом является лидер рейтинга Хостинг Ниндзя — Макхост.
Проект готов, Все проверено на локальном сервере OpenServer и можно переносить сайт на хостинг. Вот только какую компанию выбрать? Предлагаю рассмотреть хостинг fornex.com. Отличное место для твоего проекта с перспективами бурного роста.
Разработка веб-сайтов с помощью онлайн платформы Wrike
20 ресурсов для прототипирования
Подборка из нескольких десятков ресурсов для создания мокапов и прототипов.
Топ 10 бесплатных хостингов
Небольшая подборка провайдеров бесплатного хостинга с подробным описанием.