某网站做了一套评论系统,用于网站上所有的评论服务,什么文章,图片等等,评论表的大概结构如下:
CREATE TABLE `comments` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`category_id` INT UNSIGNED NOT NULL,
`content` TEXT NOT NULL
);
项目越来越庞杂,由于前期开发缺乏有效的规划,代码拷贝粘贴的现象随处可见,文章系统里做了一套单独的评论CRUD程序,图片系统里也做了一套单独的评论CRUD程序,诸如此类的情况随处可见,恰好此时产品设计人员要求加入一个楼层(floor)功能,看过网易评论的人对这个白痴功能都不会陌生。
必须要加入一个用来保存楼层的字段(单靠排序设置楼层是不可靠的,因为一旦删除某条记录就乱了):
ALTER TABLE `comments` ADD `floor` INT UNSIGNED NOT NULL DEFAULT '0';
设置一个缺省值是为了不影响已有的CRUD程序,如果没有缺省值,现有的INSERT程序就没法用了。
现在该如何修改程序代码以实现这个功能呢?每份CRUD程序都修改一遍么?!这很可能是个费力不讨好的决定,其结果八成是费了老大劲改了半天代码,结果老板还嫌你做的慢,那怎么办呢?答案就是触发器:
DELIMITER //
CREATE TRIGGER fix_floor BEFORE INSERT ON comments FOR EACH ROW
BEGIN
DECLARE _floor INTEGER;
SELECT IFNULL(MAX(floor), 0) INTO _floor FROM comments WHERE category_id = NEW.category_id;
SET NEW.floor = _floor + 1;
END; //
DELIMITER ;
需要说明的是在触发器里,需要用DELIMITER重新声明一下结束符,比如本例中的“//”,并且最好在结束时再把它恢复成缺省值,也就是“;”,另外要注意使用DECLARE声明变量的方法,还要注意的是在本例中IFNULL是必要的,不然一旦记录不存在,MAX的结果就会是NULL,把NULL复制给一个INTEGER类型的变量,结果就出错了。触发器的使用需要注意的地方还有很多,读者请参考官方文档。
说明:把业务逻辑放到数据层无疑是个含有坏味道的决定,另外,没有考虑使用锁来防止不一致问题。