I’m starting to use triggers in MySQL, and have a problem.
I wrote some Triggers that will update my users table and make notifications=notifications+1 (to a user) when I INSERT something in the notifications table. It seems to work, but I have made a ‘check-cron-script’, which runs every minute, and updates the users table with 100% true values that should be there (count from notifications table). This cron sends me an email if it updates some rows. If that script makes some change, It’ll send me an email containing the user_id which had a bad value. A while ago, I received two emails in a row (22:53, 22:54) telling me the script found a bad value in the users table, and had to update 1 row. Both emails were the same (same user, same thing). And I’m now wondering what happened.
UPDATE query:
INSERT INTO notifications (user_id,title,notification) VALUES (%i,%s,%s)
AFTER INSERT TRIGGER:
BEGIN
IF NEW.`new` > 0 THEN
UPDATE users SET notifications=notifications+1 WHERE id=NEW.user_id;
END IF;
END
AFTER UPDATE TRIGGER:
BEGIN
IF OLD.`new` != NEW.`new` THEN
IF OLD.`new` > 0 THEN
UPDATE users SET notifications=notifications-1 WHERE id=OLD.user_id;
END IF;
IF NEW.`new` > 0 THEN
UPDATE users SET notifications=notifications+1 WHERE id=NEW.user_id;
END IF;
END IF;
END
AFTER DELETE TRIGGER:
BEGIN
IF OLD.`new` > 0 THEN
UPDATE users SET notifications=notifications-1 WHERE id=OLD.user_id;
END IF;
END
notifications.new is a tinyint which indicates if the user read the notification allready (the default value is 1)
The notifications table is not being updated so frequently, so I was thinking what should have happened, and the only thing I think should happened is:
1. The UPDATE query was run
2. The cron executed before the TRIGGER, and had to change the value, cause it was wrong
3. The TRIGGER was run
4. In the next run of the cron the value was higher than it had to be, so the cron had to update it again (same user, same thing, same email)
But I really don’t know if a thing like this can happen. If the AFTER TRIGGER is delayed a bit, and if the cron can be executed after the query, but before the TRIGGER.
Triggers are atomic. Unless you’re running with
tx_isolation=READ-UNCOMMITTED, the scenario you described shouldn’t be possible.