ETJava Beta | Java    注册   登录
  • mysql 触发器

    发表于 2025-03-17 00:02:23     阅读(87)     博客类别:MySQL

    触发器介绍

    MySQL 的触发器和存储过程一样,都是嵌入到 MySQL 中的一段程序,是 MySQL中管理数据的有力工具。通过对数据表的相关操作来触发、激活从而实现执行。比如当对 student 表进行操作( INSERT, DELETE 或 UPDATE)时就会激活它执行。
    作用:
    	触发器与数据表关系密切,主要用于保护表中的数据。特别是当有多个表具有一定的相互联系的时候,触发器能够让不同的表保持数据的一致性、日志记录 , 数据校验等操作
    优点:
    	触发器的执行是自动的,当对触发器相关表的数据做出相应的修改后立即执行。
        触发器可以实施比 FOREIGN KEY 约束、CHECK 约束更为复杂的检查和操作。
        触发器可以实现表数据的级联更改,在一定程度上保证了数据的完整性。
    缺点:
    	使用触发器实现的业务逻辑在出现问题时很难进行定位,特别是涉及到多个触发器的情况下,会使后期维护变得困难。
        大量使用触发器容易导致代码结构被打乱,增加了程序的复杂性,
        如果需要变动的数据量较大时,触发器的执行效率会非常低。
           

    触发器分类

    mysql中 触发器分为三类
    	INSERT 触发器、 UPDATE 触发器和 DELETE 触发器
    	使用别名OLD和NEW来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。现在触发器还只支持行级触发不支持语句级触发

    INSERT触发器

    语法格式
    CREATE <触发器名> < BEFORE | AFTER >
    <INSERT | UPDATE | DELETE >
    ON <表名> FOR EACH Row<触发器主体>
    
    -- 创建触发器语法
    delimiter $$ -- delimiter表示触发器 $$表示将这段SQL的结束符改为$$
    create trigger 触发器名称 
    after 或 before -- 操作之前或之后触发 
    on 表名 -- 由哪张表操作触发
    for each row -- 针对每一行数据
    begin -- 触发器主体
    	-- 要执行的insert语句 NEW.userId表示使用userId作为新插入行的userId外键
    	insert into t_log values(null,NEW.userId,'操作记录',xxx,...)
    end -- 触发器主体结束
    $$ -- 触发器结束
    delimiter ; -- 将结束符改回分号
    

    创建表

    CREATE TABLE `t_user` (
       `usrId` int NOT NULL AUTO_INCREMENT,
       `uName` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
       `uEmail` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
       `uAge` int DEFAULT NULL,
       PRIMARY KEY (`usrId`)
     ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
     
     CREATE TABLE `t_points` (
       `pId` int NOT NULL AUTO_INCREMENT,
       `points` double DEFAULT NULL COMMENT '积分',
       `createTime` datetime DEFAULT NULL,
       `uId` int DEFAULT NULL,
       PRIMARY KEY (`pId`)
     ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

    创建INSERT触发器

    在新增用户时 触发添加用户积分信息
    
    -- 创建触发器
    DELIMITER $$ -- 更改默认的语句分隔符$$ 这样就可以在触发器内部使用分号作为语句分隔符
    CREATE TRIGGER after_user_insert_points -- 触发器名称 新增用户之后添加用户的积分信息
    AFTER INSERT ON t_user -- 在t_user表新增数据之后触发
    FOR EACH ROW -- 针对t_user中每一行数据
    BEGIN -- 触发器开始 触发器的主体
    	-- 要触发的操作 即 向积分表添加一条记录 注意:添加到值要与字段匹配
    	INSERT INTO t_points(points,createTime,uId) VALUES(0.00,NOW(),NEW.usrId);
    END -- 触发器主体结束
    $$ -- 触发器定义结束
    DELIMITER ; -- 将语句分隔符改回到分号
    
    -- 测试
    INSERT INTO t_user VALUES(NULL,'Tom','tom@usa.com',18);

    DELETE触发器

    思考:删除数据时 应先删除从表中数据还是主表中数据
    
    应先删除从表中数据 在删除主表中数据 否则从表中的外键就无法关联到主表
    
    触发 当用户注销时 将用户积分信息删除并同时删除主表中对应的用户信息
    
    表还是使用上边新增触发器时创建的两张表

    创建DELETE触发器

    -- 当用户注销时 删除用户记录 同时清空用户其他信息 如积分记录
    -- 正常业务操作时 应先删除用户积分记录 最后才会删除用户信息
    DELIMITER $$ -- 更改默认的语句分隔符$$ 这样就可以在触发器内部使用分号作为语句分隔符
    CREATE TRIGGER user_delete_points -- 触发器名称 新增用户之后添加用户的积分信息
    BEFORE DELETE ON t_user -- 在t_user表中数据删除之前触发
    FOR EACH ROW -- 针对t_user中每一行数据
    BEGIN -- 触发器开始 触发器的主体
    	-- old与new类似 old表示之前存在的
    	DELETE FROM t_points WHERE uId=old.usrId; 
    END -- 触发器主体结束
    $$ -- 触发器定义结束
    DELIMITER ; -- 将语句分隔符改回到分号
    
    -- 测试删除操作
    DELETE FROM t_user WHERE usrId=1;

    UPDATE触发器1

    更新数据时触发的操作
    
    修改用户信息时 同时向日志表添加一条记录
    
    用户表使用前面创建的,需要新增一张日志表

    创建t_logs表

    CREATE TABLE `t_logs` (
       `id` int NOT NULL AUTO_INCREMENT,
       `remark` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '操作描述',
       `uId` int DEFAULT NULL,
       PRIMARY KEY (`id`)
     ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

    创建UPDATE触发器

    -- 当更新用户信息时 向操作记录中添加一条日志信息
    DELIMITER $$ -- 更改默认的语句分隔符$$ 这样就可以在触发器内部使用分号作为语句分隔符
    CREATE TRIGGER user_update_trigger2 -- 触发器名称 修改用户之后添加操作记录信息
    AFTER UPDATE ON t_user -- 在t_user表中数据修改之后触发
    FOR EACH ROW -- 针对t_user中每一行数据
    BEGIN -- 触发器开始 触发器的主体
    	-- old与new类似 old表示之前存在的
    	INSERT INTO t_logs VALUES(NULL,'用户更新了数据',old.usrId);
    END -- 触发器主体结束
    $$ -- 触发器定义结束
    DELIMITER ; -- 将语句分隔符改回到分号
    
    -- 测试
    UPDATE t_user SET uEmail='Jerry@etjava.com'WHERE usrId=2;

    UPDATE触发器2

    用户的年龄不允许超过35
    
    如果超过了给出错误提示

    创建UPDATE触发器

    DELIMITER &&
    CREATE TRIGGER update_user_tip
    BEFORE UPDATE ON t_user 
    FOR EACH ROW 
    BEGIN
    	IF new.uAge>35 THEN
    	SIGNAL SQLSTATE '42002' -- SIGNAL使用大写
            SET MESSAGE_TEXT = '用户年龄不能大于35岁', -- MESSAGE_TEXT 大写
                MYSQL_ERRNO = 42002; -- MYSQL_ERRNO 大写
    	END IF;
    END
    &&
    DELIMITER ;

     

     

    多条件触发器

    DELIMITER $$ 
    CREATE TRIGGER aaa
    AFTER UPDATE ON t_a -- a表更新之后触发
    FOR EACH ROW 
    BEGIN 
    	
    	IF NEW.`status`=3 THEN
    		UPDATE t_b SET `status`=NEW.`status` WHERE aId=NEW.`aId`;
    	END IF;
    	IF NEW.`status`=4 THEN
    		UPDATE t_b SET `status`=NEW.`status` WHERE aId=NEW.`aId`;
    	END IF;
    END 
    $$ 
    DELIMITER ;