Статьи

Положите палец на триггеры в рельсах с HairTrigger

Значок конфигурации базы данных. Векторная иллюстрация

HairTrigger позволяет приложениям Ruby on Rails создавать и управлять триггерами базы данных кратко и независимо от базы данных. Без этого реализация триггеров базы данных в приложении Rails потребовала бы специальных знаний базы данных по созданию хранимых процедур с требуемыми операторами SQL для выполнения операций с базой данных.

В этой статье вам дадут краткое введение в триггеры базы данных, а также сравнение между использованием обратных вызовов Active Record и триггеров базы данных. В этой статье также объясняются ключевые моменты реализации триггеров базы данных с использованием HairTrigger. Для получения полной информации об API HairTrigger, пожалуйста, обратитесь к официальной документации .

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

Триггеры базы данных с первого взгляда

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

Денормализация с использованием триггеров базы данных

Мы будем использовать стратегию денормализации для демонстрации реализации триггера базы данных. Здесь задействованы 2 таблицы: clipsvideos Видео может иметь много клипов, а клип может принадлежать только одному видео. Денормализация включает в себя суммирование durationclipsdurationvideos

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

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

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

  • После создания клипа обновите продолжительность видео.
  • После обновления продолжительности клипа обновите продолжительность видео.
  • После удаления клипа обновите продолжительность видео.

Подводные камни триггеров базы данных

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

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

Триггеры базы данных против обратных вызовов активной записи

В то время как триггеры базы данных являются перехватчиками в жизненном цикле таблицы или представления, обратные вызовы Active Record являются перехватчиками в жизненном цикле объектов Active Record. Триггеры базы данных не должны рассматриваться как полная замена обратных вызовов Active Record. Вместо этого триггеры следует рассматривать как дополнение к обратным вызовам Active Record.

Когда использовать триггеры базы данных

Триггеры следует использовать в ситуации, когда вам нужна особая функция базы данных, которая недоступна при обратном вызове Active Record. Пока это не вводит циклическое обновление или шторм обновления данных, как упомянуто в предыдущем разделе, можно использовать триггер базы данных. Вот некоторые ключевые моменты, которые вы можете использовать при принятии решения о реализации триггеров базы данных в вашем приложении Rails:

  • Требуются атомарные операции SQL.
  • Преодоление состояния гонки, например, агрегирование данных.
  • Обеспечение ссылочной целостности в базах данных.
  • Регистрация или аудит записей базы данных.

Когда использовать обратные вызовы Active Record

С другой стороны, обратные вызовы Active Record следует использовать в ситуации, когда для них не требуется особая функция базы данных, и она доступна из Active Record. Следует также отметить, что вы должны быть очень осторожны, чтобы не вводить циклические обратные вызовы, как и проблема циклического обновления при использовании триггеров. Вот несколько случаев, когда лучше использовать обратные вызовы Active Record, а не триггеры:

  • Требуется отладка, это все равно Ruby.
  • Подключает к конкретному обратному вызову Active Record, например, перед проверкой.
  • Операция SQL, которая не вводит условия гонки.
  • Операция SQL, которая требует определенных возможностей Ruby / Rails.

Тем не менее, это может быть не полное сравнение между ними, но это должно дать вам преимущество при выборе правильной технологии, прежде чем вы начнете ее применять.

Триггеры базы данных с использованием HairTrigger

Давайте рассмотрим, как управлять триггерами с помощью гема HairTrigger, в частности, с использованием варианта денормализации и агрегирования данных. Демонстрация показала здесь пользователям следующую технологию:

  • Ruby 2.3.0
  • Rails 4.2.5.1
  • PostgreSQL 9.5.0

Любые реализации в следующих разделах не были протестированы в других средах. Если у вас другие настройки, пожалуйста, обратитесь к списку совместимости HairTrigger, прежде чем переходить к следующему разделу.

Установка

Поместите драгоценный камень в свой Gemfile:

 gem "hairtrigger"

И выполните следующую команду из корневого пути вашего приложения:

 bundle install

Вот и все, ты в порядке.

Реализация

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

  • После создания клипа обновите продолжительность видео.
  • После обновления продолжительности клипа обновите продолжительность видео.
  • После удаления клипа обновите продолжительность видео.

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

 # app/models/clip.rb
def self.update_video_duration_sql
  <<-SQL
    UPDATE videos SET duration = (
      SELECT sum(clips.duration)
      FROM clips
      WHERE clips.video_id = videos.id
    )
  SQL
end

Условие обновления может быть выполнено с помощью специальных переменных, которые являются NEWOLD Поскольку некоторые события содержат разные переменные, вы должны поместить условие обновления в каждый триггер. Пожалуйста, обратитесь к документации вашей базы данных для использования специальных переменных.

После создания клипа обновите продолжительность видео:

 # app/models/clip.rb
trigger.after(:create) do
  <<-SQL
    #{ self.update_video_duration_sql }
    WHERE videos.id = NEW.video_id
  SQL
end

После обновления продолжительности клипа обновите продолжительность видео:

 # app/models/clip.rb
trigger.after(:update).of(:duration) do
  <<-SQL
    #{ self.update_video_duration_sql }
    WHERE videos.id = NEW.video_id
  SQL
end

После удаления клипа обновите продолжительность видео:

 # app/models/clip.rb
trigger.after(:delete) do
  <<-SQL
    #{ self.update_video_duration_sql }
    WHERE videos.id = OLD.video_id
  SQL
end

Миграция базы данных

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

 bundle exec rake db:generate_trigger_migration

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

 bundle exec rake db:migrate

Каждый раз, когда вы что-то меняете внутри блока триггера, вы должны запускать задачу Rake генерации миграции триггера, иначе миграция не будет создана. Это работает так, что он будет различать операторы SQL внутри блока триггера до и после обновления кода, поэтому он может определить, следует ли создавать новую миграцию.

Вывод

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