一、实验目的与要求:
1.了解MySQL审计功能及实现方式
2.掌握触发器的工作原理、定义及操作方法
二、实验内容:
注:
- 在同一个触发器内编写多行代码,需要用结构begin ……end
- 函数current_user()获得当前登录用户名
1.自动保存对所有表(至少fruits表和orderitems表)的插入、更新、删除操作到opertaion表中。
①增加opertaion表
表1 opertaion表结构
字段名 | 字段说明 | 数据类型 | 主键 | 外键 | 非空 | 唯一 | 自增 |
id | ID号 | int (11) | Y | N | Y | Y | Y |
tablename | 表名 | varchar (50) | N | N | Y | N | N |
opname | 操作类型 | varchar (50) | N | N | Y | N | N |
optime | 操作时间 | datetime | N | N | Y | N | N |
ConnUser | 用户名 | varchar(30) | N | N | Y | N | N |
源码:
CREATE TABLE opertaion(
id INT(11) NOT NULL UNIQUE AUTO_INCREMENT,
tablename VARCHAR(50) NOT NULL,
opname VARCHAR(50) NOT NULL,
optime DATETIME NOT NULL,
ConnUser VARCHAR(30) NOT NULL,
PRIMARY KEY(id)
)
②创建基于fruits表和orderitems表的插入、更新、删除触发器,该类触发器的功能是在执行相关操作时把操作相关信息写入opertaion表中。例如在fruits表中成功插入一项新的元组后,在opertaion表中自动增加一个元组,该元组描述了是对fruits表进行了插入操作。
源码:
CREATE TRIGGER insert_f AFTER INSERT ON fruits FOR EACH ROW
INSERT INTO opertaion(tablename,opname,optime,`ConnUser`)VALUES('fruits','insert',NOW(),CURRENT_USER());
CREATE TRIGGER update_f AFTER UPDATE ON fruits FOR EACH ROW
INSERT INTO opertaion(tablename,opname,optime,`ConnUser`)VALUES('fruits','update',NOW(),CURRENT_USER());
CREATE TRIGGER delete_f AFTER DELETE ON fruits FOR EACH ROW
INSERT INTO opertaion(tablename,opname,optime,`ConnUser`)VALUES('fruits','delete',NOW(),CURRENT_USER());
CREATE TRIGGER insert_oi AFTER INSERT ON orderitems FOR EACH ROW
INSERT INTO opertaion(tablename,opname,optime,`ConnUser`)VALUES('orderitems','insert',NOW(),CURRENT_USER());
CREATE TRIGGER update_oi AFTER UPDATE ON orderitems FOR EACH ROW
INSERT INTO opertaion(tablename,opname,optime,`ConnUser`)VALUES('orderitems','update',NOW(),CURRENT_USER());
CREATE TRIGGER delete_oi AFTER DELETE ON orderitems FOR EACH ROW
INSERT INTO opertaion(tablename,opname,optime,`ConnUser`)VALUES('orderitems','delete',NOW(),CURRENT_USER());
③测试:用B001帐号(即销售人员帐号)登录,在fruits表中插入一条水果信息,再查看opertaion表是否实现自动添加更新记录。
运行测试结果截图:登录B001账号,插入数据后,opertaion表格实现自动添加更新记录,结果如下图所示:
2. 实现自动更新fruits表中商品数量
①在fruits表中增加一个属性quantity(库存商品数量) ,数据类型int(5),默认值为1000
源码:
ALTER TABLE fruits ADD quantity INT(5) DEFAULT(1000);
运行测试结果截图:
②创建触发器实现当客户下订单后,fruits表对应此商品的数量自动的发生变化(减少或增加):
具体要求:
(1)在orderitems表中修改某个订单的商品数量后时, fruits表对应此商品的数量发生相应的改变。
(2)在orderitems表中增加一个购买详单(增加一个元组)时, fruits表对应此商品的数量发生相应的改变。
源码:
(1)修改订单数量:
CREATE TRIGGER update_q AFTER UPDATE on orderitems FOR EACH ROW
UPDATE fruits SET quantity=quantity+old.quantity-new.quantity where f_id=new.f_id;
UPDATE orderitems SET quantity =50 WHERE f_id='a1';
- 增加一个购买详单:
CREATE TRIGGER insert_q AFTER INSERT ON orderitems FOR EACH ROW
UPDATE fruits SET quantity=quantity-new.quantity WHERE f_id=new.f_id;
INSERT INTO orderitems VALUES(50001,4,'x0',200,8.80);
运行测试结果截图:
修改前的fruits表格和orderitems表格
修改后的fruits表格和orderitems表格
三、实验小结
1.实验中遇到的问题及解决过程
问题:在orderitems表中修改某个订单的商品数量后时, fruits表对应此商品的数量发生相应的改变,不能对新旧数据进行判断后正确执行
解决过程:触发器经过判断,新旧字段值不一样,因此调用UPDATE fruits SET quantity=quantity+old.quantity-new.quantity where f_id=new.f_id;
实现对于数据的修改。
2.实验中产生的错误及原因分析
错误:在通过B001账号登录时,在fruits表中插入一条水果信息,查看opertaion表是自动添加更新记录的ConnUser为root@localhost而不是B001。
原因分析:在MySQL中,CURRENT_USER()函数返回的是当前连接的用户名,而不是执行SQL语句的用户。在创建触发器时,此时的CURRENT_USER()返回的是root@localhost,因为执行这个触发器的账号是root。如果想让ConnUser字段显示插入记录的用户,需要在应用程序中获取并传递这个信息。例如,可以在插入数据时,将用户信息作为参数传递给存储过程或函数,然后在存储过程中使用这个参数来插入数据。