MySql存储过程参考

Mysql(9)---纪录一次实际开发过程中用到的复杂存储过程

为了尽可能的还原当时为什么需要用到存储过程,下面我写了个详细的文档,我们可以从需求文档出发来分析。

有关存储过程之前也写了两篇文章来做铺垫。
LOOP 及 LEAVE、ITERATE
这里LOOP用来标记循环;
而LEAVE表示离开循环,好比编程里面的break一样;
ITERATE则继续循环,好比编程里面的continue一样。

1、Mysql(7)---存储过程

2、Mysql(8)---游标

一、需求背景

一个服装类的app商城,用户会员等级分:普通会员,vip会员,钻石会员

现在在app上发布一款商品,但发布是可以设置该商品是 所有会员可见,还是 指定会员可见

现在要见3张表

1、商品表
2、会员表
3、商品关联会员表

这个时候,又有一个优惠券功能,同样可以设置该优惠券是 所有会员可见,还是 指定会员可见

需要再建两张表

1、优惠券表
2、优惠券关联会员表

然而,这时候又发布一个礼品,同样可以设置该礼品是 所有会员可见,还是 指定会员可见

又需要建两张表

1、礼品表
2、礼品关联会员表

......

思考: 这里面我们发现可以优化的地方

1、每一次需要用到会员表信息的时候,都需要建一个关联表。
2、在编辑商品的时候,会员名称回显的时候,一般是两步。
    1) 需要带着这个商品ID,去商品会员关联表中查询所有会员的ID
    2)再拿着这些会员ID,去会员表中获取会员其它信息回显给用户。 

优化: 针对上面两点这里面我们可以思考。

1、把N多的关联信息表,变成一张表。
2、写一个公共接口,拿着ID去查会员信息就可以,而不需要管这个ID是商品ID还是礼品ID.....

那么这个时候问题就来了,之前的数据已经保存到相应的关联表中了,如果迁移数据首先考虑下面两个问题

问题

1、如何把之前所有的关联表数据迁移到同一张表中?

2、如果只是把所有关联表数据复制到到同一张表中,ID有没有可能重复?

针对以上,就需要存储过程来完成了,因为前期数据已经保存到不同的关联表中了,现在需要放到同一张表中。

二、表建立

先建表,至于最终需要什么效果,文档也会说明

一共有5张表

1、商品表

说明:key_id字段后面解释作用

/**
 * 1、商品表 并插入数据
 */
CREATE TABLE `mall_pro` (
  `mall_id` char(32) NOT NULL,
  `pro_name` varchar(32) DEFAULT NULL COMMENT ‘显示名称‘,
  `cash_cost` double(10,1) DEFAULT ‘0.0‘ COMMENT ‘商品价格‘,
  `show_member` int(1) DEFAULT ‘0‘ COMMENT ‘显示 0所有会员 1指定会员‘,
  `status` int(1) DEFAULT ‘1‘ COMMENT ‘状态:1正常 0删除‘,
  `key_id` varchar(32) DEFAULT ‘0‘ COMMENT ‘会员控件表key‘,
  PRIMARY KEY (`mall_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘商品表‘;

INSERT INTO `mall_pro` (`mall_id`, `pro_name`, `cash_cost`, `show_member`, `status`, `key_id`)
VALUES
    (‘1‘,‘手表‘,100.0,0,1,‘0‘),
    (‘2‘,‘手机‘,888.0,1,1,‘0‘),
    (‘3‘,‘电脑‘,3888.0,1,1,‘0‘);

2、会员表

CREATE TABLE `member` (
  `member_id` char(32) NOT NULL,
  `member_grade` varchar(32) DEFAULT NULL COMMENT ‘会员等级‘,
  `status` int(1) DEFAULT ‘1‘ COMMENT ‘状态:1正常 0删除‘,
  PRIMARY KEY (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘会员表‘;

INSERT INTO `member` (`member_id`, `member_grade`, `status`)
VALUES
    (‘1‘,‘普通会员‘,1),
    (‘2‘,‘银卡会员‘,1),
    (‘3‘,‘金卡会员‘,1);

3、商品关联会员表

CREATE TABLE `mall_pro_member` (
  `id` char(32) NOT NULL,
  `mall_id` varchar(32) DEFAULT NULL COMMENT ‘商品ID‘,
  `member_id` varchar(32) DEFAULT NULL COMMENT ‘会员ID‘,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘商品关联会员表‘;

INSERT INTO `mall_pro_member` (`id`, `mall_id`, `member_id`)
VALUES
    (‘1‘,‘2‘,‘1‘),
    (‘2‘,‘2‘,‘2‘),
    (‘3‘,‘3‘,‘2‘);

4、新建统一管理关联会员的表

CREATE TABLE `member_widget_relation` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘主键‘,
  `key_id` varchar(32) NOT NULL DEFAULT ‘‘ COMMENT ‘KeyID‘,
  `member_id` varchar(32) NOT NULL DEFAULT ‘‘ COMMENT ‘会员表ID‘,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘控件关联会员表‘;

5、会员控件表key

说明为什么要建这张表?

上面说过了,如果都直接把所有关联会员表的数据直接复制到member_widget_relation有可能会ID重复的可能。具体步骤下面会说。

CREATE TABLE `member_widget` (
  `key_id` varchar(32) NOT NULL DEFAULT ‘‘,
  PRIMARY KEY (`key_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

需求步骤

1)生成一个随机UUID,当member_widget(会员控件表key)的主键。

2)生成纪录的同时把这个UUID,放到mall_pro(商品表)key_id字段中。

3) 把mall_pro_member(商品关联会员表)数据迁移到member_widget_relation(新建统一管理关联会员的表)中,只不过把关联的mall_id换成key_id

4)下次取该商品的会员信息,只要拿着这个key_idmember_widget_relation取就可以了。

三、存储过程实践

下面我直接把我写好的存储过程贴出来。

drop  PROCEDURE  if  exists  member_process; #在没有重新申明结束标志之前 都是以 ; 结束。
DELIMITER $ # 申明结束标志
CREATE PROCEDURE member_process ()
BEGIN
  # 创建接收游标数据的变量
    DECLARE keyId varchar(32);
    DECLARE mallId varchar(32);
    # 创建结束标志变量
    DECLARE done int DEFAULT false;
    #创建游标 获取mall_id和key_id的集合
    DECLARE coup_cur CURSOR FOR
        SELECT mall_id, key_id
        FROM mall_pro
        WHERE show_member = 1 AND status = 1;
    # 指定游标循环结束时的返回值
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true;
    # 打开游标
    OPEN coup_cur;
    # 开始循环游标里的数据
    loop_a: LOOP
   # 根据游标当前指向的一条数据 插入到上面申明的局部变量中
        FETCH coup_cur INTO mallId, keyId;
        IF done THEN
            LEAVE loop_a;
        END IF;
        # 为什么是0 因为keyId为后面新增字段所以之前的老数据默认都为0,只有新数据key_id才不为0
        IF keyId = 0 THEN
          # 开启事物 先把数据保存后提交事物
            START TRANSACTION;
            # 生成随机UUID
            SET keyId = REPLACE(UUID(), ‘-‘, ‘‘);
            # 插入member_widget表中
            INSERT INTO member_widget (key_id) VALUES (keyId);
            # 同时把keyId更新到mall_pro表中
            UPDATE mall_pro SET key_id = keyId WHERE mall_id = mallId;
            COMMIT;
            # 接下来的BEGIN 所做的事情就是把mall_pro_member数据的迁移到member_widget_relation中
            BEGIN
                DECLARE memberId varchar(32);
                DECLARE done1 int DEFAULT false;
                # 取出mall_pro_member表中的关联数据
                DECLARE coup_cur1 CURSOR FOR
                    SELECT member_id FROM mall_pro_member WHERE mall_id = mallId;
                DECLARE CONTINUE HANDLER FOR NOT FOUND SET done1 = true;
                OPEN coup_cur1;
                loop_b: LOOP
                    FETCH coup_cur1 INTO memberId;
                    IF done1 THEN
                        LEAVE loop_b;
                    END IF;
                    # 插入到member_widget_relation表中
                    INSERT INTO member_widget_relation (key_id, member_id) VALUES (keyId, memberId);
                END LOOP loop_b;
            END;
        END IF;
    END LOOP loop_a;
END$
# 运行存储过程
call member_process()$

来看运行结果:

1、mall_pro(商品表)

我们可以看到show_member为1的数据的key_id已经改变。

2、member_widget会员控件表key)

发现生成了两条纪录,而且key_id和mall_pro中的key_id一一对应。

3、member_widget_relation(新建统一管理关联会员的表)

完美的将mall_pro_member(商品关联会员表)中的数据迁移过来,同时mall_pro_id也换成了key_id

真实环境其实比这个还复杂,不过大致思路就是这样。

完美!结束!谢幕!

只要自己变优秀了,其他的事情才会跟着好起来(少将11)

原文地址:https://www.cnblogs.com/LoveShare/p/12024302.html

时间: 2024-10-19 03:53:54

MySql存储过程参考的相关文章

转 mysql 存储过程初探

https://www.cnblogs.com/qmfsun/p/4838032.htmlMySQL命令执行sql文件的两种方法 https://www.cnblogs.com/mark-chan/p/5384139.html CREATE PROCEDURE GreetWorld() SELECT CONCAT(@greeting,' World');SET @greeting='Hello';CALL GreetWorld(); https://blog.csdn.net/shaochens

mybatis调用mysql存储过程返回结果集

存储过程中经常需要返回结果集. Mysql 中直接用 select 即可返回结果集.而 oracle 则需要使用游标来返回结果集.这一点 Mysql 相对比较方便,如下代码即可实现输出结果集: 存储过程定义: DELIMITER $$ DROP procedure IF EXISTS pro_sql_data1 $$ CREATE procedure pro_sql_data1(in sear_name varchar(2000)) BEGIN if sear_name is not null

mysql 存储过程的应用

1引言 你点击了桌面上的Chrome图标,一个浏览器窗口出现了,输入网址就可以在Internet世界愉快玩耍.这一切是怎么实现的呢?Chromium这个多进程的程序是如何启动各个进程的呢?浏览器主进程(界面进程)启动了哪些线程?如何启动的呢?这些问题一直萦绕在心头,一起来看看源代码吧.本文主要针对Chromium for Mac的源代码,其它操作系统大同小异. 2背景知识 浏览器作为一个应用程序,是以进程的形式运行在操作系统上的.首先,Chromium是一个多进程的应用程序,我们需要了解Chro

Mysql存储过程包含事务,且传入sql数据执行

有一个需求是:在一个图片按钮上点击,在按钮的上方弹出一个弹框,根据弹框的内容页面做不同的显示.这个其实没什么难的,主要是要控制好弹框的显示位置,让弹框显示在图片的正上方的中间. 一开始是用的Popupwindow,但是Popupwindow不能给弹窗之外的页面加一个半透明的蒙层,当然可以在页面上加一个专门的作为蒙层的View,但是很显然,这么做会代码变得很恶心,于是又换成了Dialog,因为Dialog弹出的时候会自动加一个蒙层的,但是这个时候,弹框显示位置的Y坐标不对了,后来一顿查,原来Dia

mysql 存储过程错误调试记录

 mysql存储过程错误调试记录 公司平台在mysql数据库上运行,一些存储过程报错,调试过程痛苦,记录错误及解决办法,供参考. 调试环境:dbForge Studio for MySQL 6.1版本,试用版: 1.BIZ_GET_ORGAN_BY_CONDITION 问题1:提示递归调用错误,递归次数太多:根据业务设置,最大255: [email protected]@max_sp_recursion_depth = 10; 常见如乱码造成导致条件失效,出现死循环: 问题2:变量的内容是乱

mysql 存储过程入门

这篇文章主要介绍了MySql存储过程与函数详解,内容很详细,需要的朋友可以参考下 存储过程和函数是在数据库中定义一些SQL语句的集合,然后直接调用这些存储过程和函数来执行已经定义好的SQL语句.存储过程和函数可以避免开发人员重复的编写相同的SQL语句.而且,存储过程和函数是在MySQL服务器中存储和执行的,可以减少客户端和服务器端的数据传输.一.存储过程1.1.基本语法 CREATE PROCEDURE sp_name ([proc_parameter[,...]])     [characte

Mysql存储过程调用

mysql存储过程实例教程 发布时间:2014-04-09编辑:JB01 这篇文章主要介绍了mysql存储过程的使用方法,mysql存储过程实例教程,有需要的朋友参考下. 1.1create  procedure  (创建)create procedure存储过程名 (参数列表)   beginsql语句代码块end注意:由括号包围的参数列必须总是存在.如果没有参数,也该使用一个空参数列().每个参数默认都是一个in参数.要指定为其它参数,可在参数名之前使用关键词 out或inout在mysql

mysql存储过程动态执行SQL

CREATE PROCEDURE feeMonth(in fmark varchar(200),in fuser char(32),in ftime BIGINT,in fmonth char(6)) BEGIN #定义SQL变量 declare create_sql varchar(100); declare sel_sql varchar(100); declare del_sql varchar(100); declare fmon varchar(100); #定义表名变量 declar

MySQL 存储过程错误处理

MySQL  存储过程错误处理 如何使用MySQL处理程序来处理在存储过程中遇到的异常或错误. 当存储过程中发生错误时,重要的是适当处理它,例如:继续或退出当前代码块的执行,并发出有意义的错误消息. MySQL提供了一种简单的方法来定义处理从一般条件(如警告或异常)到特定条件(例如特定错误代码)的处理程序. 声明处理程序 要声明一个处理程序,您可以使用DECLARE HANDLER语句如下: DECLARE action HANDLER FOR condition_value statement