منطق داخل دیتابیس: ابزاری دولبه
MySQL میتواند کد را خودش اجرا کند: رویه (Procedure)، تابع (Function)، تریگر و رویداد زمانبندیشده (Event). این ابزارها قدرتمندند، اما منطقی که داخل دیتابیس است در git و code review و تستهای برنامه کمتر دیده میشود و ORM جنگو از آن خبر ندارد.
| ابزار | مناسب برای | نامناسب برای |
|---|---|---|
| Procedure | عملیات دستهای نزدیک داده، بستن ماه مالی | منطق کسبوکار روزمره |
| Function | محاسبهی کوچک و قطعی مثل متراژ | کوئری درون تابع که در WHERE صدا زده شود |
| Trigger | یکدستسازی داده، لاگ ممیزی | ارسال پیامک یا منطق پیچیده |
| Event | پاکسازی دورهای جدولها | کارهایی که نیاز به پایش و تکرار دارند |
Procedure با خطای کنترلشده
DELIMITER $$
CREATE PROCEDURE reserve_stock(IN p_product_id INT UNSIGNED, IN p_qty INT UNSIGNED)
BEGIN
UPDATE products SET stock = stock - p_qty
WHERE id = p_product_id AND stock >= p_qty;
IF ROW_COUNT() = 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'insufficient stock';
END IF;
END$$
DELIMITER ;
CALL reserve_stock(7, 2);
Function و Trigger
CREATE FUNCTION carpet_area_m2(p_width_cm INT, p_length_cm INT)
RETURNS DECIMAL(8,2) DETERMINISTIC NO SQL
RETURN ROUND(p_width_cm * p_length_cm / 10000, 2);
-- یکدست کردن ی و ک عربی پیش از ذخیره
DELIMITER $$
CREATE TRIGGER customers_bi BEFORE INSERT ON customers
FOR EACH ROW
BEGIN
SET NEW.full_name = REPLACE(REPLACE(NEW.full_name, 'ي', 'ی'), 'ك', 'ک');
END$$
DELIMITER ;
همین تریگر را برای BEFORE UPDATE هم بسازید؛ وگرنه ویرایش نام دوباره حروف عربی را وارد میکند. تریگر در اینجا مناسب است چون داده از چند مسیر (پنل، API، ورود از اکسل) وارد میشود و دیتابیس تنها نقطهی مشترک است.
Event: نظافت شبانه
CREATE EVENT purge_done_jobs
ON SCHEDULE EVERY 1 DAY STARTS '2026-10-03 03:30:00'
DO DELETE FROM jobs
WHERE status = 'done' AND finished_at < NOW() - INTERVAL 30 DAY;
SHOW EVENTS FROM carpet_factory;
قاعدهی سرانگشتی: قیدهایی که «هر برنامهای» باید رعایت کند و پاکسازیهای ساده را در دیتابیس بگذارید؛ منطق کسبوکار را در کد برنامه که تست و نسخهبندی میشود.
نکتههایی که کمتر کسی میداند
- تریگرها برای تغییراتی که با
ON DELETE CASCADEکلید خارجی انجام میشوند اجرا نمیشوند؛ لاگ ممیزی مبتنی بر تریگر این حذفها را نمیبیند. - با binlog روشن، ساخت تابع بدون یکی از عبارتهای
DETERMINISTIC،NO SQLیاREADS SQL DATAخطای 1418 میدهد. DELIMITERدستور کلاینتmysqlاست، نه SQL؛ درRunSQLمایگریشن جنگو یا درایور پایتون، CREATE PROCEDURE را بدون آن و بهصورت یک دستور بفرستید.- روتینها بهطور پیشفرض با مجوزهای DEFINER اجرا میشوند؛ اگر آن کاربر حذف شود، با ERROR 1449 از کار میافتند.
SQL SECURITY INVOKERاین وابستگی را برمیدارد. - Eventها روی replica با وضعیت
SLAVESIDE_DISABLEDساخته میشوند تا دوبار اجرا نشوند؛ بعد از جایگزینی replica بهجای source، آنها را دستی فعال کنید.