• MySQL----存储过程


    基本命令

    #声明变量
    DECLARE a INT;
    #对变量赋值
    SET a = 5;

    基本使用

    创建存储过程

    DROP PROCEDURE if exists p8;
    CREATE PROCEDURE p8 ()
    BEGIN
        DECLARE a INT;
        DECLARE b INT;
        DECLARE @TIMES INT;--
        SET a = 5;
        SET b = 5;
        INSERT INTO user(name, age) VALUES (a,b);
        select * from user;
    
    END;

    调用存储过程

    call p8();

    游标

    • 游标的声明需要在所有其他变量之后,游标常常要配合一个状态值来实现功能,需要声明一个休止标识
    • declare continue handler for not found set 休止标识=1;
    • 游标使用要先open,最后需要close
    • 游标值的获取用fetch my_cursor into 某变量

    基本使用

    delimiter $$
    CREATE procedure changeName()
        begin
            declare stopflag int default 0;
            declare myname varchar(20) default '';
            declare my_cursor cursor for select sname from student where sid%2=0;
            declare continue handler for not found set stopflag=1;
            open my_cursor;
            while(stopflag=0) do
                begin
                    fetch my_cursor into myname;
                    update student set sname = concat(sname,'aab') where sname = myname;
                end;
            end while;
                close my_cursor;
            end;
    $$ 
    

      

    利用存储过程进行秒杀

    实用有并发,但是并发量不大,请求压力在后台。如果高并发的情况下,需要做额外的处理

    建表

    -- 整个项目的数据库脚本
    -- 开始创建一个数据库
    CREATE DATABASE seckill;
    -- 使用数据库
    USE seckill;
    -- 创建秒杀库存表
    CREATE TABLE seckill(
      `seckill_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '商品库存ID',
      `name` VARCHAR(120) NOT NULL COMMENT '商品名称',
      `number` INT NOT NULL COMMENT '库存数量',
      `start_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() COMMENT '秒杀开启的时间',
      `end_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() COMMENT '秒杀结束的时间',
      `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() COMMENT '创建的时间',
      PRIMARY KEY (seckill_id),
      KEY idx_start_time(start_time),
      KEY idx_end_time(end_time),
      KEY idx_create_time(create_time)
    )ENGINE =InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='秒杀库存表';
    
    -- 插入初始化数据
    
    insert into
      seckill(name,number,start_time,end_time)
    values
      ('1000元秒杀iphone6',100,'2016-5-22 00:00:00','2016-5-23 00:00:00'),
      ('500元秒杀iPad2',200,'2016-5-22 00:00:00','2016-5-23 00:00:00'),
      ('300元秒杀小米4',300,'2016-5-22 00:00:00','2016-5-23 00:00:00'),
      ('200元秒杀红米note',400,'2016-5-22 00:00:00','2016-5-23 00:00:00');
    
    -- 秒杀成功明细表
    -- 用户登录相关信息
    create table success_killed(
      `seckill_id` BIGINT NOT NULL COMMENT '秒杀商品ID',
      `user_phone` BIGINT NOT NULL COMMENT '用户手机号',
      `state` TINYINT NOT NULL DEFAULT -1 COMMENT '状态标示:-1无效 0成功 1已付款',
      `create_time` TIMESTAMP NOT NULL COMMENT '创建时间',
      PRIMARY KEY (seckill_id,user_phone), /*联合主键*/
      KEY idx_create_time(create_time)
    )ENGINE =InnDB DEFAULT CHARSET =utf8 COMMENT ='秒杀成功明细表'
    

    建立存储过程

    -- 秒杀执行储存过程
    DELIMITER $$ -- console ; 转换为
    $$
    -- 定义储存过程
    -- 参数: in 参数   out输出参数
    -- row_count() 返回上一条修改类型sql(delete,insert,update)的影响行数
    -- row_count:0:未修改数据 ; >0:表示修改的行数; <0:sql错误
    CREATE PROCEDURE `seckill`.`execute_seckill`
      (IN v_seckill_id BIGINT, IN v_phone BIGINT,
       IN v_kill_time  TIMESTAMP, OUT r_result INT)
      BEGIN
        DECLARE insert_count INT DEFAULT 0;
        START TRANSACTION;
      #先插入,seckill_id, user_phone建立了主键,如果重复插入会报错,我们使用IGNORE,忽略重复插入,如果重复插入,SELECT row_count()返回0,就会rollback;
      INSERT IGNORE INTO success_killed
        (seckill_id, user_phone, create_time)
        VALUES (v_seckill_id, v_phone, v_kill_time);
        SELECT row_count()
        INTO insert_count;
        IF (insert_count = 0)
        THEN
          ROLLBACK;
          SET r_result = -1;
        ELSEIF (insert_count < 0)
          THEN
            ROLLBACK;
            SET r_result = -2;
        ELSE
          #更新仓库数量,如果更新成功,SELECT row_count()返回值>0,就可以继续走;
          UPDATE seckill
          SET number = number - 1
          WHERE seckill_id = v_seckill_id
                AND end_time > v_kill_time
                AND start_time < v_kill_time
                AND number > 0;
          SELECT row_count()
          INTO insert_count;
          IF (insert_count = 0)
          THEN
            ROLLBACK;
            SET r_result = 0;
          ELSEIF (insert_count < 0)
            THEN
              ROLLBACK;
              SET r_result = -2;
          ELSE
            COMMIT;
            SET r_result = 1;
    
          END IF;
        END IF;
      END;
    $$

    测试

    set  @r_result =111;
    CALL execute_seckill(1003, 13502172891, now(), @r_result);
    SELECT @r_result;

    在mapper接口

    void killByProcedure(Map<String,Object> paramMap);
    

    xml

    <!--调用储存过程-->
        <select id="killByProcedure" statementType="CALLABLE">
            CALL execute_seckill(
                    #{seckillId,jdbcType=BIGINT,mode=IN},
                    #{phone,jdbcType=BIGINT,mode=IN},
                    #{killTime,jdbcType=TIMESTAMP,mode=IN},
                    #{result,jdbcType=INTEGER,mode=OUT}
            )
    </select>

    ps:关于select row_count(),在控制台可以测试出来,返回上一次update,insert,delete影响行数。

    if not exists注意事项

    在if not exists中出现异常,不会报错,直接跳出if判断。所以很容易出现问题,尽量少用,参考上面(秒杀)使用。

    delimitr $$
    CREATE PROCEDURE `test_proc`(
        pid int
    )
    begin
        if not exists (select * from t where id=pid) then
            insert into t(id) values(pid);
        end if;
        
        update t set total=total+1 where id=pid;
    end $$
    delimiter ; 
    

      

  • 相关阅读:
    C# 文本,图片 与 Base64的相互转换
    vue3.x 中的自定义组件及使用
    vue 的TodoList 小Demo
    vue中的条件渲染 v-show、v-if、v-else、v-else-if
    vue 使用$refs获取表单内容及v-model双向数据绑定
    python-异常处理&操作数据库&网络编程
    python-接口开发
    python-数据库&邮件
    python-函数和模块
    python-函数&list&dic&集合&文件读取
  • 原文地址:https://www.cnblogs.com/yanxiaoge/p/13746323.html
Copyright © 2020-2023  润新知