• MySQL高级:存储过程


    存储过程

    存储过程是一个包括多条SQL语句的集合,专用于特定表的特定操作,比如我们之前实战项目中的创建用户,那么我们就需要一次性为两张表添加数据,但是如果不使用Java,而是每次都去使用SQL命令来完成,就需要手动敲两次命令,非常麻烦,因此我们可以提前将这些操作定义好,预留出需要填写数据的位置,下次输入参数直接调用即可。

    这里很容易与函数搞混淆,存储过程也是执行多条SQL语句,但是它们的出发点不一样,函数是专用于进行数据处理,并将结果返回给调用者,它更多情况下是一条SQL语句的参与者,无法直接运行,并且不涉及某个特定表:

     

    select count(*) from student;

    而存储过程是多条SQL语句的执行者,这是它们的本质区别。

    定义存储过程与定义函数极为相似,它也可以包含参数,函数中使用的语句这里也能使用,但是它没有返回值:

    1. CREATE PROCEDURE lbwnb(`name` VARCHAR(20), pwd VARCHAR(255))
    2. BEGIN
    3. INSERT INTO users(username, `password`) VALUES(`name`, pwd);
    4. END

    我们可以在存储过程中编写多条SQL语句,但是注意,MySQL的存储过程不具有原子性,当出现错误时,并不会回滚之前的操作,因此需要我们自己来编写事务保证原子性。

    接着我们来看看如何执行存储过程:

    CALL lbwnb('111', '2222')

    通过使用call来执行一个存储过程,如果存储过程有参数,那么还需要填写参数。

    比如现在我们想要实现查询用户表,如果包含用户test那么就删除用户,如果不包含,就添加用户:

    1. CREATE PROCEDURE `lbwnb`()
    2. BEGIN
    3. IF NOT EXISTS(SELECT * FROM users WHERE username = 'test') THEN
    4. INSERT INTO users(username, `password`) VALUES('test', '123456');
    5. ELSE
    6. DELETE FROM users WHERE username = 'test';
    7. END IF;
    8. END

    这里其实只需要一个简单的IF判断即可实现。

    那么如果我们希望遍历一个SELECT语句查询的结果呢?我们可以使用游标来完成:

    1. BEGIN
    2. DECLARE id INT;
    3. DECLARE `name` VARCHAR(10);
    4. DECLARE sex VARCHAR(5);
    5. DECLARE cur CURSOR FOR SELECT * FROM student;
    6. OPEN cur;
    7. WHILE TRUE DO
    8. FETCH cur INTO id, `name`, sex;
    9. SELECT id, `name`, sex;
    10. END WHILE;
    11. CLOSE cur;
    12. END

    游标的使用分为4个步骤:

    • DECLARE 游标名称 CURSOR FOR 查询结果   -  定义游标
    • OPEN cur     -   开启游标
    • FETCH 游标名称 INTO 存储结果的变量    -    从顶部开始,每执行一次,向下移动,如果已经在最底部,则触发异常
    • CLOSE cur    -   关闭游标

    我们这里利用了一个while循环来多次通过游标获取查询结果,但是最后是因为出现异常才退出的,这样会导致之后的代码就无法继续正常运行了。

    我们接着来看如何处理异常:

    1. BEGIN
    2. DECLARE id INT;
    3. DECLARE `name` VARCHAR(10);
    4. DECLARE sex VARCHAR(5);
    5. DECLARE score INT;
    6. DECLARE a INT DEFAULT 0;
    7. DECLARE cur CURSOR FOR SELECT * FROM student;
    8. -- 必须在游标定义之后编写
    9. DECLARE CONTINUE HANDLER FOR 1329 SET a = 1;
    10. OPEN cur;
    11. WHILE a = 0 DO
    12. FETCH cur INTO id, `name`, sex, score;
    13. SELECT id, `name`, sex, score;
    14. END WHILE;
    15. CLOSE cur;
    16. SELECT 1;
    17. END

    我们可以声明一个异常处理器(句柄),格式如下:

    • declear (continue/exit) handler for 异常名称(ID) 做点什么

    我们还可以限定存储过程的参数传递,比如我们只希望用户给我们一个参数用于接收数据,而不是值传递,我们可以将其设定为OUT类型:

    1. CREATE PROCEDURE `lbwnb`(OUT a INT)
    2. BEGIN
    3. SELECT a;
    4. SET a = 100;
    5. END

    所有的参数默认为IN类型,也就是只能作为传入参数,无法为其赋值,而这里讲参数设定为OUT类型,那么参数无法将值传入,而只能被赋值。

    如果我们既希望参数可以传入也可以被重新赋值,我们可以将其修改为INOUT类型。

  • 相关阅读:
    UI设计师的主要工作内容优漫动游
    11. [containerd] content服务解析
    git commit 的规范
    SSM毕设项目 - 基于SSM的房屋出租出售系统(含源码+论文)
    【云原生 | 23】Docker运行Web服务实战之Tomcat
    springboot+vue网上生鲜超市系统java
    单商户商城系统功能拆解39—分销应用—分销等级
    了解什么是JDBC
    Ansible相关内容梳理
    MindSpore的tile算子性能问题
  • 原文地址:https://blog.csdn.net/Leon_Jinhai_Sun/article/details/126921986