为什么需要存储过程
当今的软件大都应用于网络中,而一般应用程序所需数据都保存在数据库中。在没有使用存储过程的数据库应用程序中,用户所编写的应用程序都是从本地计算机(client)向服务器(server)端发送SQL代码来请求对数据库中数据的增删改差操作,服务器对接收到的SQL代码进行编译后执行,并将结果返回给client,再由客户端的软件处理后输出。如果开发者对服务器安全性考虑不周全,就会为黑客提供盗取数据的机会。其中SQL注入是一种常见的方式。
为了防止SQL注入过程泄露企业的商业机密,我们可以通过存储过程把对数据库操作的SQL代码预先编译好并保存在服务器端。这样既减少了网络传输量,又能保证应用程序的运行性能。
然后,我们来看下什么是存储过程
什么是存储过程
存储过程(procedure)类似于C#语言中的方法,它是SQL语句和控制语句的预编译集合。存储过程保存在数据库里,可由应用程序调用执行。
说的简单一点,存储过程就像数据库中运行的方法
存储过程的优点:
- 执行速度更快---因为存储过程是预编译过的
- 模块化程序设计—类似方法的复用
- 提高系统的安全性—防止SQL注入
- 减少网络流量—只需传输存储过程的名称即可
存储过程分类:
系统存储过程:
系统存储过程提供了管理数据和更新表的机制,并充当从系统表中检索信息的快捷方式。
常用系统存储过程:
用户自定义存储过程:
除了使用系统存储过程外,用户还可以创建自己的存储过程。
常见存储过程的语法:
CREATE PROC[EDURE] 存储过程名
@参数1 数据类型 = 默认值 OUTPUT,
@参数n 数据类型 = 默认值 OUTPUT
AS
SQL语句
参数说明:
- 参数可选
- 参数分为输入参数、输出参数
- 输入参数允许有默认值
如何执行存储过程
EXEC 过程名 [参数]
这里提示一点:如果存储过程存在输出参数,一定要写Exec
说了这么多,下面我们一起来写一个分页的存储过程
create proc GetPageList
@pageIndex int,--页码
@pageSize int,--页容量(每页显示几条记录)
@pageCount int output,--总页数
@rowCount float output--总行数
as
select * from
(
select ROW_NUMBER() over(order by studentNo) as num,* from Student
) as temp where num between (@pageIndex-1)*@pageSize+1 and @pageIndex*@pageSize
select @rowCount=COUNT(*) from Student
set @pageCount=ceiling(@rowCount/@pageSize)
declare @pageCount int,@rowCount int
exec GetpageList 2,5,@pageCount output,@rowCount output
select @pageCount
select @rowCount
接下来简单看下触发器的相关知识
触发器
触发器的作用:自动化操作,减少了手动操作以及出错的几率
触发器是一种特殊类型的存储过程,它不同于前面介绍的一般的存储过程。一般的存储过程名称被直接调用,而触发器主要是通过事件进行触发而被执行
触发器是一个功能强大的工具,在表中数据发生变化时自动强制执行。
一旦表 发生新增/修改/删除 操作,那么就来自动执行一行代码
常见的触发器
DML触发器:
Insert、delete、update(不支持select) 要执行的操作
After触发器(for)、instead of触发器(不支持before触发器) 操作的时间(什么时候操作)
After(for):操作完成后才调用此触发器
Instead of :操作完成前调用此触发器
可以对一张表创建多个触发器,但是一般不这样用
注意:instead of替换新增语句的操作,之后新增操作不再更新到数据表。
如果向数据库插入多条数据呢?
会触发多次
After触发器和instead of触发器的器区别
After触发器:
- 在语句执行完毕之后触发
- 按语句触发 ,而不是所影响的行数,无论影响多少行,只触发一次。,
- 只能建立在常规表上,不能建立在视图和临时表上。
- 可以递归触发,最高可达32级。
Instead of 触发器
01,用来替换原来的操作
02,不会递归触发
03,可以建在表和视图上
指定执行触发器而不是执行触发 SQL 语句,从而替代触发语句的操作。
Inserted表与deleted表
Inserted表只能用在触发器中
Inserted 表包含新数据
Insert、update触发器会用到
Deleted表包含旧数据
Delete、update触发器会用到
常用语法
CREATE TRIGGER triggerName ON 表名
after(for)(for与after都表示after触发器) | instead of
UPDATE|INSERT|DELETE(insert,update,delete)
AS
begin
…
end
接下来我们来看一个after触发器的例子
--针对班级表的新增操作触发器
create TRIGGER tg_grade ON grade
after-- after(操作完成后才调用此触发器)
INSERT--UPDATE|INSERT|DELETE
AS
begin
--触发器代码
select * into studentbackup from inserted
--select * from inserted--保存了引发新增触发器的新增数据,只能在触发器中访问
End
这个触发器的作用:当向grade表中新增一条数据时,会将刚插入的数据备份到studentbackup中,其中studentbackup表必须不存在!
实例:
建立2张表格employee和department,他们以员工ID建立关系
1. 创建2表:
create table employee (
employee_id int(5) primary key not null,
employee_name varchar(20),
employee_salary int(5));
create table department (
dept_id int(3),
dept_name varchar(20),
employee_id int(5),
constraint fk_employee_id foreign key(employee_id) references employee(employee_id));
2. 给employee创建添加记录的存储过程
在这之前,需要设置一下分隔符,以免后面使用;时就终止了创建
delimiter //
create procedure add_employee(in id int,in name varchar(20),in salary int) /*参数输入的形式,in:输入,若为输出,则为out*/
begin
insert into employee values(id,name,salary); #输入的数据插入到表格中
select * from employee;
end// #这里就以//结束程序的录入
3.给department创建添加记录的存储过程
create procedure insert_dept(in id int,in name varchar(20),in emp_id int)
begin
insert into department values(id,name,emp_id);
select * from department;
end;//
4. 调用存储过程完成数据录入
call add_employee(2,'Jason',6500);//
call insert_dept(1,'STE',2);//
5.创建一个给指定部门员工加薪的存储过程
create procedure raise (in department_id int,in add_salary_amount int)
begin
update employee set employee_salary=employee_salary+add_salary_amount
where employee_id in ( select employee_id from department where department_id=dept_id);
commit;
end;//
call raise(1,200);//
6. 记录员工薪资变更日志
这时就可以对salary创建一个触发器,记录变更信息,先创建一个记录日志的表格:
create table salary_adjust_log(
employee_id int(5),
old_salary int(4),
new_salary int(4),
changedata datetime);// #使用datetime格式记录变更时间
创建触发器:
create trigger update_salary
after update on employee
for each row #对表格每一行执行
begin
insert into salary_adjust_log
values(new.employee_id, /*new:表示更新后的记录,old:更新前的记录,在oracle中语法是 :new.employee_id,:old employee_salary,多了个冒号*/
old.employee_salary,
new.employee_salary,
now()); #使用now()函数记录时间
end;//
7. 查看salary_adjust_log
create procedure see_changelog()
select * from salary_adjust_log;//
call see_changelog();//
来源:https://www.cnblogs.com/TaoLeonis/p/7158853.html