Mysql(9)---紀錄一次實際開發過程中用到的復雜存儲過程
為了盡可能的還原當時為什么需要用到存儲過程,下面我寫了個詳細的文檔,我們可以從需求文檔出發來分析。
有關存儲過程之前也寫了兩篇文章來做鋪墊。
一、需求背景
一個服裝類的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
字段中。
- 把
mall_pro_member(商品關聯會員表)
數據遷移到member_widget_relation(新建統一管理關聯會員的表)
中,只不過把關聯的mall_id
換成key_id
。
4)下次取該商品的會員信息,只要拿着這個key_id
到member_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)