MySQL中使用signal命令中断触发器执行

MySQL中使用signal命令中断触发器执行

如果需要中断触发器的执行,可以使用signal语句抛出一个异常,并向处理程序,应用程序的外部部分或客户端提供错误信息。

一、signal语法

创建触发器基本语法如下:

signal sqlstate | condition_name;
set condition_information_item_name_1 = value_1,
    condition_information_item_name_1 = value_2, etc;

说明:

signal关键字是由declare condition语句声明的sqlstate值或条件名称。如果需要向调用者提供提示信息,可使用set子句。
condition_information_item_name可以是messge_text,mysql_errorno,cursor_name等。

二、数据准备

创建两张表:商品(goods)和订单(orders),表结构如下:

create table goods(
    goods_id int primary key auto_increment comment '商品编号',
    goods_name varchar(50) not null default '' comment '商品名称',
    model char(20) not null default '' comment '型号',
    specifications char(20) not null default '' comment '规格',
    unit char(20) not null default '' comment '单位',
    inventory_number decimal(10,2) not null default 0 comment '库存数量'
);

create table orders(
    orders_id int primary key auto_increment comment '订单编号',
    goods_id int not null default 0 comment '商品编号',
    number decimal(10,2) not null default 0 comment '订购数量'
);

create table orders_logs(
    orders_logs_id int primary key auto_increment comment '日志编号',
    orders_id int comment '订单编号',
    goods_id int not null default 0 comment '商品编号',
    number decimal(10,2) not null default 0 comment '订购数量',
    opt_method varchar(50) not null default '' comment '操作方式',
    state varchar(50) not null default '' comment '操作状态',
    user_name varchar(50) not null default '' comment '操作人员',
    opt_time datetime comment '操作时间'
);

为goods表插入以下数据:

insert into goods(goods_name,model,specifications,unit,inventory_number)
values('移动硬盘','S001-500','500GB','个',20),('移动硬盘','S001-1000','1TGB','个',15),
('笔记本','HPSV001-C','I7-16GB-1TB','台',5),('台式机','LX-S-V1','I5-4GB','台',6),
('U盘','KS-16','16GB','个',200),('U盘','KS-32','32GB','个',200),
('U盘','KS-64','64GB','个',200);

mysql> select * from goods;
+----------+--------------+-----------+----------------+------+------------------+
| goods_id | goods_name   | model     | specifications | unit | inventory_number |
+----------+--------------+-----------+----------------+------+------------------+
|        1 | 移动硬盘     | S001-500  | 500GB          | 个   |            20.00 |
|        2 | 移动硬盘     | S001-1000 | 1TGB           | 个   |            15.00 |
|        3 | 笔记本       | HPSV001-C | I7-16GB-1TB    | 台   |             5.00 |
|        4 | 台式机       | LX-S-V1   | I5-4GB         | 台   |             6.00 |
|        5 | U盘          | KS-16     | 16GB           | 个   |           200.00 |
|        6 | U盘          | KS-32     | 32GB           | 个   |           200.00 |
|        7 | U盘          | KS-64     | 64GB           | 个   |           200.00 |
+----------+--------------+-----------+----------------+------+------------------+
7 rows in set (0.00 sec)

三、为orders表创建触发器

(一)创建before insert触发器

delimiter //

drop trigger if exists t_before_insert_orders;
create trigger t_before_insert_orders
before insert on orders 
for each row
begin
    declare orders_goods_id int;
    declare goods_inventory_number decimal(10,2);
    declare orders_goods_name varchar(50);
    declare msg varchar(100);
    if not exists(select goods_name from goods where goods_id=new.goods_id) then
    	set msg='你订购的商品不存在!请重新下订单!';
    	signal sqlstate '45000' set message_text=msg;
    end if;
    
    select inventory_number,goods_name into goods_inventory_number,orders_goods_name 
    from goods where goods_id=new.goods_id;
    if goods_inventory_number<new.number then
    	set msg=concat(orders_goods_name,'库存不足,请修改订购商品的数量!');
    	signal sqlstate '45000' set message_text=msg;
    else
    	update goods set inventory_number=inventory_number-new.number where goods_id=new.goods_id;
    end if;
end //

delimiter ;

说明:
1、该触发器在生成新订单之前检查订购商品的数量是否超出库存量,如果超出库存,则该订单无法生成。
2、如果订购量小于库存量,则生成新订单,同时使用new关键字取出新订单订购的商品编号和订购数量。用【new.goods_id】从goods表查询商品,用【new.number】修改商品的库存量。

(二)创建after insert触发器

delimiter //

drop trigger if exists t_after_insert_orders;
create trigger t_after_insert_orders
after insert on orders 
for each row
begin
    insert into orders_logs(orders_id,goods_id,number,opt_method,state,user_name,opt_time)
	values(new.orders_id,new.goods_id,new.number,'生成新订单','添加订单成功',user(),now());
end //

delimiter ;

说明:
1、before insert触发器和after insert执行的顺序为:(1)before insert触发器;(2)操作记录;(3)after insert触发器。
2、如果before insert触发器出现异常,则操作记录会失败,而after insert触发器也会中断执行。
3、如果生成新订单(插入订单)成功,则before insert触发器没有出现异常,after insert触发器执行,在orders_logs表中插入新订单的信息。
生成如下订单,查看goods表的数据变动情况:

mysql> select * from goods;
+----------+--------------+-----------+----------------+------+------------------+
| goods_id | goods_name   | model     | specifications | unit | inventory_number |
+----------+--------------+-----------+----------------+------+------------------+
|        1 | 移动硬盘     | S001-500  | 500GB          | 个   |            20.00 |
|        2 | 移动硬盘     | S001-1000 | 1TGB           | 个   |            15.00 |
|        3 | 笔记本       | HPSV001-C | I7-16GB-1TB    | 台   |             5.00 |
|        4 | 台式机       | LX-S-V1   | I5-4GB         | 台   |             6.00 |
|        5 | U盘          | KS-16     | 16GB           | 个   |           200.00 |
|        6 | U盘          | KS-32     | 32GB           | 个   |           200.00 |
|        7 | U盘          | KS-64     | 64GB           | 个   |           200.00 |
+----------+--------------+-----------+----------------+------+------------------+
7 rows in set (0.00 sec)

mysql> insert into orders(goods_id,number) values(10,1);
ERROR 1644 (45000): 你订购的商品不存在!请重新下订单!
mysql> insert into orders(goods_id,number) values(4,50);
ERROR 1644 (45000): 移动硬盘库存不足,请修改订购商品的数量!
mysql> insert into orders(goods_id,number) values(1,2);
Query OK, 1 row affected (0.01 sec)
mysql> insert into orders(goods_id,number) values(5,20);
Query OK, 1 row affected (0.01 sec)
mysql> insert into orders(goods_id,number) values(5,5);
Query OK, 1 row affected (0.01 sec)
mysql> insert into orders(goods_id,number) values(5,15);
Query OK, 1 row affected (0.01 sec)


mysql> select * from orders;
+-----------+----------+--------+
| orders_id | goods_id | number |
+-----------+----------+--------+
|         1 |        1 |   2.00 |
|         2 |        5 |  20.00 |
|         3 |        5 |   5.00 |
|         4 |        5 |  15.00 |
+-----------+----------+--------+
4 rows in set (0.00 sec)

mysql> select * from goods;
+----------+--------------+-----------+----------------+------+------------------+
| goods_id | goods_name   | model     | specifications | unit | inventory_number |
+----------+--------------+-----------+----------------+------+------------------+
|        1 | 移动硬盘     | S001-500  | 500GB          | 个   |            18.00 |
|        2 | 移动硬盘     | S001-1000 | 1TGB           | 个   |            15.00 |
|        3 | 笔记本       | HPSV001-C | I7-16GB-1TB    | 台   |             5.00 |
|        4 | 台式机       | LX-S-V1   | I5-4GB         | 台   |             6.00 |
|        5 | U盘          | KS-16     | 16GB           | 个   |           160.00 |
|        6 | U盘          | KS-32     | 32GB           | 个   |           200.00 |
|        7 | U盘          | KS-64     | 64GB           | 个   |           200.00 |
+----------+--------------+-----------+----------------+------+------------------+
7 rows in set (0.00 sec)

mysql> select orders_id,goods_id,number,opt_method,state,user_name,opt_time from orders_logs;
+-----------+----------+--------+-----------------+--------------------+----------------+---------------------+
| orders_id | goods_id | number | opt_method      | state              | user_name      | opt_time            |
+-----------+----------+--------+-----------------+--------------------+----------------+---------------------+
|         1 |        1 |   2.00 | 生成新订单      | 添加订单成功       | root@localhost | 2019-11-24 12:02:32 |
|         2 |        5 |  20.00 | 生成新订单      | 添加订单成功       | root@localhost | 2019-11-24 12:04:22 |
|         3 |        5 |   5.00 | 生成新订单      | 添加订单成功       | root@localhost | 2019-11-24 12:04:28 |
|         4 |        5 |  15.00 | 生成新订单      | 添加订单成功       | root@localhost | 2019-11-24 12:04:30 |
+-----------+----------+--------+-----------------+--------------------+----------------+---------------------+
4 rows in set (0.00 sec)

可以看出,如果商品编号不存在,或者订购量大于库存量都会返回出错信息。当1号生成订单之后,1号商品的库存减少了2个。同时在orders_logs文件中生成一条记录。2号、3号和4号订单共订购40个5号商品,因此5号商品的数量由200变成了160个。同时把订单信息存放在orders_logs文件中。

(三)创建after delete触发器

delimiter //

drop trigger if exists t_after_delete_orders;
create trigger t_after_delete_orders
after delete on orders 
for each row
begin
    update goods set inventory_number=inventory_number+old.number where goods_id=old.goods_id;
    insert into orders_logs(orders_id,goods_id,number,opt_method,state,user_name,opt_time)
	values(old.orders_id,old.goods_id,old.number,'删除订单','删除订单成功',user(),now());
end //

delimiter ;

说明:取消订单(删除订单)时,使用old关键字取出要删除订单的订单号、订购的商品编号、订购数量。用【old.goods_id】从goods表查询商品,用【old.number】修改商品的库存量。同时把该订单的信息记录到orders_logs表中。
下面取消(删除)4号订单,结果如下:

mysql> select * from orders;
+-----------+----------+--------+
| orders_id | goods_id | number |
+-----------+----------+--------+
|         1 |        1 |   2.00 |
|         2 |        5 |  20.00 |
|         3 |        5 |   5.00 |
|         4 |        5 |  15.00 |
+-----------+----------+--------+
4 rows in set (0.00 sec)

mysql> select * from goods;
+----------+--------------+-----------+----------------+------+------------------+
| goods_id | goods_name   | model     | specifications | unit | inventory_number |
+----------+--------------+-----------+----------------+------+------------------+
|        1 | 移动硬盘     | S001-500  | 500GB          | 个   |            18.00 |
|        2 | 移动硬盘     | S001-1000 | 1TGB           | 个   |            15.00 |
|        3 | 笔记本       | HPSV001-C | I7-16GB-1TB    | 台   |             5.00 |
|        4 | 台式机       | LX-S-V1   | I5-4GB         | 台   |             6.00 |
|        5 | U盘          | KS-16     | 16GB           | 个   |           160.00 |
|        6 | U盘          | KS-32     | 32GB           | 个   |           200.00 |
|        7 | U盘          | KS-64     | 64GB           | 个   |           200.00 |
+----------+--------------+-----------+----------------+------+------------------+
7 rows in set (0.00 sec)

mysql> delete from orders where orders_id=4;
Query OK, 1 row affected (0.01 sec)

mysql> select * from orders;
+-----------+----------+--------+
| orders_id | goods_id | number |
+-----------+----------+--------+
|         1 |        1 |   2.00 |
|         2 |        5 |  20.00 |
|         3 |        5 |   5.00 |
+-----------+----------+--------+
3 rows in set (0.00 sec)

mysql> select * from goods;
+----------+--------------+-----------+----------------+------+------------------+
| goods_id | goods_name   | model     | specifications | unit | inventory_number |
+----------+--------------+-----------+----------------+------+------------------+
|        1 | 移动硬盘     | S001-500  | 500GB          | 个   |            18.00 |
|        2 | 移动硬盘     | S001-1000 | 1TGB           | 个   |            15.00 |
|        3 | 笔记本       | HPSV001-C | I7-16GB-1TB    | 台   |             5.00 |
|        4 | 台式机       | LX-S-V1   | I5-4GB         | 台   |             6.00 |
|        5 | U盘          | KS-16     | 16GB           | 个   |           175.00 |
|        6 | U盘          | KS-32     | 32GB           | 个   |           200.00 |
|        7 | U盘          | KS-64     | 64GB           | 个   |           200.00 |
+----------+--------------+-----------+----------------+------+------------------+
7 rows in set (0.00 sec)

mysql> select orders_id,goods_id,number,opt_method,state,user_name,opt_time from orders_logs;
+-----------+----------+--------+-----------------+--------------------+----------------+---------------------+
| orders_id | goods_id | number | opt_method      | state              | user_name      | opt_time            |
+-----------+----------+--------+-----------------+--------------------+----------------+---------------------+
|         1 |        1 |   2.00 | 生成新订单      | 添加订单成功       | root@localhost | 2019-11-24 12:02:32 |
|         2 |        5 |  20.00 | 生成新订单      | 添加订单成功       | root@localhost | 2019-11-24 12:04:22 |
|         3 |        5 |   5.00 | 生成新订单      | 添加订单成功       | root@localhost | 2019-11-24 12:04:28 |
|         4 |        5 |  15.00 | 生成新订单      | 添加订单成功       | root@localhost | 2019-11-24 12:04:30 |
|         4 |        5 |  15.00 | 删除订单        | 删除订单成功       | root@localhost | 2019-11-24 12:13:56 |
+-----------+----------+--------+-----------------+--------------------+----------------+---------------------+
5 rows in set (0.00 sec)

(四)创建befor update触发器

delimiter //

drop trigger if exists t_before_update_orders;
create trigger t_before_update_orders
before update on orders 
for each row
begin
    declare goods_inventory_number decimal(10,2);
    declare orders_goods_name varchar(50);
    declare msg varchar(100);
    
    select inventory_number,goods_name into goods_inventory_number,orders_goods_name 
    from goods where goods_id=new.goods_id;
    if goods_inventory_number+old.number<new.number then
    	set msg=concat(orders_goods_name,'库存不足,无法更改订购数量,请修改订购商品的数量!');
    	signal sqlstate '45000' set message_text=msg;
    else
    	update goods set inventory_number=inventory_number+old.number-new.number 
    	where goods_id=new.goods_id;
    end if;
end //

delimiter ;

(五)创建after update触发器

delimiter //

create trigger trigger_after_update_orders
after update on orders 
for each row
begin
    insert into orders_logs(orders_id,goods_id,number,opt_method,state,user_name,opt_time)
	values(new.orders_id,new.goods_id,new.number,
    '更新订单',concat('已将订单的订购数量由',old.number,'更改为',new.number),user(),now());
end //

delimiter ;

该触发器使用【old.goods_id】取出订单中订购的商品编号,用【old.number】取出订单修改前的订购量,用【new.number】取出订单修改后的订购量,并对商品的库存量进行更新。
把3号订单(订购的是5号商品)的订购量由5个修改为35个,查看goods表的数据变动情况:

mysql> select * from orders;
+-----------+----------+--------+
| orders_id | goods_id | number |
+-----------+----------+--------+
|         1 |        1 |   2.00 |
|         2 |        5 |  20.00 |
|         3 |        5 |   5.00 |
+-----------+----------+--------+
3 rows in set (0.00 sec)

mysql> select * from goods;
+----------+--------------+-----------+----------------+------+------------------+
| goods_id | goods_name   | model     | specifications | unit | inventory_number |
+----------+--------------+-----------+----------------+------+------------------+
|        1 | 移动硬盘     | S001-500  | 500GB          | 个   |            18.00 |
|        2 | 移动硬盘     | S001-1000 | 1TGB           | 个   |            15.00 |
|        3 | 笔记本       | HPSV001-C | I7-16GB-1TB    | 台   |             5.00 |
|        4 | 台式机       | LX-S-V1   | I5-4GB         | 台   |             6.00 |
|        5 | U盘          | KS-16     | 16GB           | 个   |           175.00 |
|        6 | U盘          | KS-32     | 32GB           | 个   |           200.00 |
|        7 | U盘          | KS-64     | 64GB           | 个   |           200.00 |
+----------+--------------+-----------+----------------+------+------------------+
7 rows in set (0.00 sec)

mysql> update orders set number=35 where oders_id=3;
ERROR 1054 (42S22): Unknown column 'oders_id' in 'where clause'
mysql> update orders set number=35 where orders_id=3;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from orders;
+-----------+----------+--------+
| orders_id | goods_id | number |
+-----------+----------+--------+
|         1 |        1 |   2.00 |
|         2 |        5 |  20.00 |
|         3 |        5 |  35.00 |
+-----------+----------+--------+
3 rows in set (0.00 sec)

mysql> select * from goods;
+----------+--------------+-----------+----------------+------+------------------+
| goods_id | goods_name   | model     | specifications | unit | inventory_number |
+----------+--------------+-----------+----------------+------+------------------+
|        1 | 移动硬盘     | S001-500  | 500GB          | 个   |            18.00 |
|        2 | 移动硬盘     | S001-1000 | 1TGB           | 个   |            15.00 |
|        3 | 笔记本       | HPSV001-C | I7-16GB-1TB    | 台   |             5.00 |
|        4 | 台式机       | LX-S-V1   | I5-4GB         | 台   |             6.00 |
|        5 | U盘          | KS-16     | 16GB           | 个   |           145.00 |
|        6 | U盘          | KS-32     | 32GB           | 个   |           200.00 |
|        7 | U盘          | KS-64     | 64GB           | 个   |           200.00 |
+----------+--------------+-----------+----------------+------+------------------+
7 rows in set (0.00 sec)

mysql> select orders_id,goods_id,number,opt_method,state,user_name,opt_time from orders_logs;
+-----------+----------+--------+-------------+-----------------------+----------------+---------------------+
| orders_id | goods_id | number | opt_method  | state                 | user_name      | opt_time            |
+-----------+----------+--------+-------------+-----------------------+----------------+---------------------+
|         1 |        1 |   2.00 | 生成新订单   | 添加订单成功            | root@localhost | 2019-11-24 12:02:32 |
|         2 |        5 |  20.00 | 生成新订单   | 添加订单成功            | root@localhost | 2019-11-24 12:04:22 |
|         3 |        5 |   5.00 | 生成新订单   | 添加订单成功            | root@localhost | 2019-11-24 12:04:28 |
|         4 |        5 |  15.00 | 生成新订单   | 添加订单成功            | root@localhost | 2019-11-24 12:04:30 |
|         4 |        5 |  15.00 | 删除订单     | 删除订单成功           | root@localhost | 2019-11-24 12:13:56 |
|         3 |   5 |35.00 | 更新订单 | 已将订单的订购数量由5.00更改为35.00| root@localhost | 2019-11-24 12:28:54 |
+-----------+----------+--------+-----------------+-------------------+----------------+---------------------+
6 rows in set (0.00 sec)

发布了44 篇原创文章 · 获赞 48 · 访问量 5407

猜你喜欢

转载自blog.csdn.net/weixin_44377973/article/details/103223264