📒
PostgreSQLのトリガーについて知ったのでサクッとメモ
背景
ER図: list_items と lists のリレーション
1つの list に複数の list_item が紐づく「1対多」のリレーションが構築されています。
list_itemsのレコードが挿入された時にlist_idと同じ値であるlist_itemsのidを持つレコードのupdated_atを更新したいです。
案1 アプリケーション側で更新する
if _, err := tx.Update("lists").
Set(goqu.Record{"updated_at": goqu.L("NOW()")}).
Where(goqu.C("id").Eq(listID)).
Executor().ExecContext(ctx); err != nil {
return err
}
確かにこれで実現はできますが、今後何らかの原因で更新漏れを起こすことが考えられそうです。
次にlist_itemsのレコードが挿入された時にlist_idと同じ値であるlist_itemsのidを持つレコードのupdated_atを自動的に更新する案を考えます。
案2 PostgreSQL の INSERT トリガーを使う
トリガーとは
PostgreSQLにおけるトリガーは、特定のテーブルで指定されたイベント(Insert、Update、Delete)発生時に自動的に実行される処理を定義するものです。
データベース内での操作を自動化し、データの一貫性を保つのに役立ちます。
新しい target_list_items が挿入されるたびに、対応する target_lists.updated_at を 自動で最新の created_at に更新 するトリガーを作成します
CREATE OR REPLACE FUNCTION update_lists_updated_at()
RETURNS TRIGGER AS $$
BEGIN
UPDATE lists
SET updated_at = NEW.created_at
WHERE id = NEW.list_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER update_lists
BEFORE INSERT ON list_items
FOR EACH ROW
EXECUTE FUNCTION update_lists_updated_at();
アプリケーション側のコードを変更しなくても、このロジックがデータベース内で適用されます。
複雑なロジックの場合は、案1のようにアプリケーション側で制御した方が良いのかなとも思いました。
参考
最後に
- DB周り、バックエンド共に知識が浅いので少しずつ力をつけたいです。
- 助言あればコメントいただきたいです。
Discussion