Как только проект окончательно принят, он становится устаревшим в смысле своих концепций.


29.08.2009, 20:40

Триггеры в БД

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



Теория

Итак, триггеры - это функции, которые срабатывают при определённых операциях. Точнее не совсем функции, а то, что связывает события с определёнными функциями. Если говорить более простым языком, то триггер запускает хранимую процедуру базы данных при определённых условиях.
Триггер всегда ассоциируется с таблицами, тоесть какой-либо триггер мы "прикрепляем" к определённой таблице.
К примеру, запрос INSERT может запускать какую-любо функцию, например обрабатывающую вставляемые данные.
Триггер можно "повесить" только на запросы INSERT, UPDATE, DELETE. На SELECT триггер уставновить невозможно. Также при создании триггера определяется время его срабатывания, до (BEFORE) или после (AFTER) срабатываемого события.



Преимущества

Скорость работы. Триггерами можно значительно уменьшить количество обращений клиента к серверу БД.
На примере PHP, допустим у нас есть 2 последовательных запроса:
pg_query("INSERT.. ");
pg_query("INSERT.. ");
После первого запроса клиент (в данном случае скрипт PHP) ждёт ответа от БД. Пока он его не дождётся, второй запрос выполнен не будет. На это уходит определённое время. Зачастую эти 2 запроса (или намного больше) можно объеденить и использовать только один INSERT. Второй INSERT будет полностью обработан сервером БД, и скрипту PHP в данном примере придётся дождаться только одного ответа от сервера. Разницу легко почувствовать при создании ресурсоёмких приложений, где используется множество запросов.

Гибкость. Не знаю, как там в мускуле, а в PostgreSQL и других продвинутых БД, например Oracle, можно писать хранимые процедуры на множестве классических языках и скриптовых языках. Вот кое-что, на чём можно писать хранимки в PostgreSQL:
Чистый SQL
PL/pgSQL - это встроенный процедурный язык постгри, достаточно простой и удобный.
Lua
Perl
LOLCODE
Php (да, даже на PHP можно, когда узнал сам охуел)
Python
Ruby
sh (рай для фанатов консоли, можно писать на любом шелле, например на bash)
Tcl
C++
Java
и прочая хуйня..!

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

Безопасность. Использование триггеров (ну и вообще хранимых процедур) позволяет легко ограничить пользователя в каких-либо действиях. Резко снижается вероятность SQL-инъекций, ведь в хранимой процедуре, используемой триггеров, вы наверняка ещё раз проверите входные параметры.



Практика

Преимущества использования триггеров сложно описать без примеров, поэтому сразу к делу.
Пример абсолютно реальный, он используется на этом сайте.
Таблица статей, в ней обратите внимание на поле comments (integer)
CREATE TABLE articles
(
  id integer NOT NULL,
  title character varying(100),
  txt text,
  data timestamp without time zone,
  comments integer DEFAULT 0,
  tags text,
  CONSTRAINT articles_pkey PRIMARY KEY (id)
)
WITH (OIDS=FALSE);

Чтобы при выводе статей мне каждый раз не считать кол-во комметариев к ней, я беру их из поля comments. А вот поле это уже изменяется триггерами при добавлении комментариев или их удалении.
Структура таблицы комментариев.
CREATE TABLE comments
(
  id integer NOT NULL,
  usr integer,
  txt text,
  data timestamp without time zone,
  article integer,
  CONSTRAINT comments_pkey PRIMARY KEY (id),
  CONSTRAINT comments_article_fkey FOREIGN KEY (article)
      REFERENCES articles (id) MATCH SIMPLE (вот нужный нам вторичный ключ)
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT comments_usr_fkey FOREIGN KEY (usr)
      REFERENCES users (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (OIDS=FALSE);


Итак, вот сама процедура, которая обновлеят кол-во комментариев с таблице статей.
CREATE OR REPLACE FUNCTION add_comment()
  RETURNS trigger AS
$BODY$
DECLARE
    x    integer;
BEGIN
SELECT count(*) INTO x FROM comments WHERE article=NEW.article AND usr=NEW.usr
    AND EXTRACT(EPOCH FROM CAST(now()-data AS INTERVAL))<=10;
IF x!=0 THEN
    RETURN OLD;
ELSE
    UPDATE articles SET comments=comments+1 WHERE id=NEW.article; -вот оно
    UPDATE users SET comments=comments+1 WHERE id=NEW.usr; - а тут обновляем общее кол-во комментирий пользователя
    RETURN NEW;
END IF;
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE

эту хуйню хранимку я написал на plpgsql.
Тут ключевое слово NEW. Можно считать, что это строка вставляемая в таблицу( в данном случае articles).
после NEW. сразу идёт название поля, думаю тут всё понятно.

Далее вешаем сам триггер на таблицу комментариев, который свяжет событие вставки новых комментариев с выполнением этой хранимой процедуры. Код до туспости маленький
CREATE TRIGGER add_comment_tgr
  BEFORE INSERT
  ON comments
  FOR EACH ROW
EXECUTE PROCEDURE add_comment();


тут ключевое BEFORE INSERT, что стоит понимать как "до добавления данных". Тоесть, данный триггер сработает при запросе INSERT на таблицу COMMENTS, причём именно ДО добавления строки. Хотя для этого случая можно было повесить и после добавления.
Соответственно подобно вашеются триггера на запросы DELETE и UPDATE.


Вот так всё просто. Буду рад вопросам и комментариям.

Комментарии


Стаьи по базам данных в Delphi

http://codingrus.ru/readarticle.php?article_id=755


Да разница-то, дельфи или хуельфи какая.. с бд надо не на клиенте, а на сервере работать)
А вообще, стриптагс у меня тут, ссылку вляпть не получится нормально..
Вы должны зарегистрироваться, чтобы оставлять комментарии

Строительство и проектирование объектов. Нижний Новгород


Rambler's Top100