zoukankan      html  css  js  c++  java
  • 存储过程和触发器

    为什么需要存储过程

        当今的软件大都应用于网络中,而一般应用程序所需数据都保存在数据库中。在没有使用存储过程的数据库应用程序中,用户所编写的应用程序都是从本地计算机(client)向服务器(server)端发送SQL代码来请求对数据库中数据的增删改差操作,服务器对接收到的SQL代码进行编译后执行,并将结果返回给client,再由客户端的软件处理后输出。如果开发者对服务器安全性考虑不周全,就会为黑客提供盗取数据的机会。其中SQL注入是一种常见的方式。

    为了防止SQL注入过程泄露企业的商业机密,我们可以通过存储过程把对数据库操作的SQL代码预先编译好并保存在服务器端。这样既减少了网络传输量,又能保证应用程序的运行性能。

    然后,我们来看下什么是存储过程

    什么是存储过程

         存储过程(procedure)类似于C#语言中的方法,它是SQL语句和控制语句的预编译集合。存储过程保存在数据库里,可由应用程序调用执行。

    说的简单一点,存储过程就像数据库中运行的方法

    存储过程的优点:

    1. 执行速度更快---因为存储过程是预编译过的
    2. 模块化程序设计—类似方法的复用
    3. 提高系统的安全性—防止SQL注入
    4. 减少网络流量—只需传输存储过程的名称即可

    存储过程分类:

       系统存储过程:

           系统存储过程提供了管理数据和更新表的机制,并充当从系统表中检索信息的快捷方式。

    常用系统存储过程:

     用户自定义存储过程:

    除了使用系统存储过程外,用户还可以创建自己的存储过程。

    常见存储过程的语法:

    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触发器:

    1. 在语句执行完毕之后触发
    2. 按语句触发 ,而不是所影响的行数,无论影响多少行,只触发一次。,
    3. 只能建立在常规表上,不能建立在视图和临时表上。
    4. 可以递归触发,最高可达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();//   

  • 相关阅读:
    .Net 多线程小结
    VIM 入门操作
    C语言中的数据
    对scanf和printf的研究!!
    C语言常用的编程规范
    ORACLE GOLDEN GATE oracle同步数据至kafka
    mysql5.7关于使用到OR是否会用到索引并提高查询效率的探讨
    sysbench安装
    percona数据库监控工具的安装部署
    redhat6 快速部署percona
  • 原文地址:https://www.cnblogs.com/TaoLeonis/p/7158853.html
Copyright © 2011-2022 走看看