Database Triggers
Also Known As
AFTER INSERT
BEFORE UPDATE
database trigger
row-level trigger
TL;DR
Stored procedures that fire automatically on INSERT, UPDATE, or DELETE — useful for audit logs and enforcing constraints, but dangerous when they become hidden business logic.
Explanation
Triggers execute SQL logic automatically when data changes. Common legitimate uses: audit trails (log who changed what and when), denormalised counter updates (post_count on user table), enforcing complex constraints not expressible as check constraints, and maintaining summary tables. Dangers: invisible side effects (application writes one row, trigger writes five more), performance surprises (a simple INSERT triggers complex logic), testing difficulty (tests must set up trigger state), and debugging complexity (unexpected data changes have invisible causes).
Diagram
sequenceDiagram
participant APP as PHP App
participant DB as Database
participant TRG as Trigger
participant LOG as Audit Log
APP->>DB: UPDATE orders SET status='shipped'
DB->>TRG: AFTER UPDATE fires automatically
TRG->>LOG: INSERT into order_audit_log
TRG-->>DB: complete
DB-->>APP: 1 row updated
Note over APP,TRG: App wrote 1 row<br/>trigger wrote 1 more<br/>developer may not know
Common Misconception
✗ Triggers are good for keeping derived data in sync — the outbox pattern or application-level events are more transparent and testable; triggers hide logic that developers must know exists.
Why It Matters
Invisible trigger logic causes mysterious data changes — a developer deletes a row, three other rows change via trigger, and debugging takes hours because the trigger is not visible in application code.
Common Mistakes
- Complex business logic in triggers — impossible to unit test and invisible to application developers.
- Triggers that call external services — synchronous triggers block the transaction; use the outbox pattern.
- Cascading triggers — trigger A fires trigger B which fires trigger C; debugging is nearly impossible.
- Not documenting that triggers exist — future developers modify the table unaware of side effects.
Code Examples
✗ Vulnerable
-- Trigger hiding business logic:
CREATE TRIGGER after_order_insert
AFTER INSERT ON orders FOR EACH ROW
BEGIN
-- Sends email (makes HTTP call from trigger!)
-- Updates inventory across 3 tables
-- Calculates customer loyalty points
-- Updates denormalised reporting tables
END;
-- Developer INSERT INTO orders... has no idea this fires
✓ Fixed
-- Trigger for legitimate audit only:
CREATE TRIGGER audit_order_updates
AFTER UPDATE ON orders FOR EACH ROW
BEGIN
INSERT INTO order_audit_log
(order_id, old_status, new_status, changed_at, changed_by)
VALUES (OLD.id, OLD.status, NEW.status, NOW(), @current_user);
END;
-- Business logic stays in PHP where it's testable and visible
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
16 Mar 2026
Edited
22 Mar 2026
Views
40
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Amazonbot 12
Perplexity 10
Google 4
Unknown AI 3
Ahrefs 2
Majestic 2
Meta AI 1
Also referenced
How they use it
crawler 31
crawler_json 1
pre-tracking 2
Related categories
⚡
DEV INTEL
Tools & Severity
🟡 Medium
⚙ Fix effort: Medium
⚡ Quick Fix
Avoid triggers for business logic — they fire invisibly, making application behaviour hard to trace and test; use PHP application events instead for audit logging and side effects
📦 Applies To
PHP 5.0+
web
cli
🔗 Prerequisites
🔍 Detection Hints
Business logic in DB triggers invisible to application; trigger modifying data causing unexpected behaviour; performance issue from trigger overhead
Auto-detectable:
✗ No
mysql-workbench
pgadmin
⚠ Related Problems
🤖 AI Agent
Confidence: Medium
False Positives: Medium
✗ Manual fix
Fix: Medium
Context: File
Tests: Update
CWE-89