什么是存储过程?
存储过程就是作为可执行对象存放在数据库中的一个或多个SQL命令。
简化: 能完成一定操作的一组SQL语句。
存储过程的优点
- 存储过程只在创造时进行编译, 之后每次执行存储过程都不需要再重新编译, 而一般SQL语句每执行一次就编译一次, 所以使用存储过程可提高数据执行速度。
- 当对数据库进行复杂操作时, 可将此复杂操作存储过程封装起来与数据库提供的事务处理综合一起使用。
- 存储过程可以重复使用, 可减少数据库开发人员的工作量。
- 安全性高, 可设定只有某些用户才具有对指定存储过程的使用权。
存储过程的缺点
- 往往定制化于特定的数据库上,因为支持的编程语言不同。当切换到其他厂商的数据库系统时,需要重写原有的存储过程。
- 存储过程的性能调校与撰写,受限于各种数据库系统。
模板及关键语法
-
创建存储过程模板
CREATE [DEFINER = { user | CURRENT_USER }] -- 定义有权限调用此存储过程的用户, 只有super用户才能使用definer PROCEDURE sp_name ([proc_parameter[,...]]) -- 存储过程名 [characteristic ...] routine_body -- 特征性的路由本体 proc_parameter: -- 存储过程参数 [ IN | OUT | INOUT ] param_name type -- 输入输出 的参数类型 characteristic: -- 特征描述 COMMENT 'string' | LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER } routine_body: Valid SQL routine statement -- 有效的路由声明 [begin_label:] BEGIN [statement_list] …… END [end_label]
-
关键语法
-
声明语句结束符, 可自定义:
DELIMITER $$ 或 DELIMITER //
-
声明存储过程:
CREATE PROCEDURE my_proc(IN p_in int) -- 输入参数为int类型的p_in
-
存储过程开始和结束符号
BEGIN .... END
-
变量赋值
SET @p_in=1
-
变量定义
DECLARE l_int int unsigned default 4000000;
-
创建mysql存储过程、存储函数
create procedure 存储过程名(参数)
-
存储过程体:
create function 存储函数名(参数)
-
Demo
-
我是从之前的test数据库中复制了一份表数据过来的, 如果你没有此表可以参考以下建表语句:
-- ---------------------------- -- Table structure for locations -- ---------------------------- DROP TABLE IF EXISTS `locations`; CREATE TABLE `locations` ( `location_id` int(11) NOT NULL AUTO_INCREMENT, `street_address` varchar(40) CHARACTER SET gb2312 COLLATE gb2312_chinese_ci NULL DEFAULT NULL, `postal_code` varchar(12) CHARACTER SET gb2312 COLLATE gb2312_chinese_ci NULL DEFAULT NULL, `city` varchar(30) CHARACTER SET gb2312 COLLATE gb2312_chinese_ci NULL DEFAULT NULL, `state_province` varchar(25) CHARACTER SET gb2312 COLLATE gb2312_chinese_ci NULL DEFAULT NULL, `country_id` varchar(2) CHARACTER SET gb2312 COLLATE gb2312_chinese_ci NULL DEFAULT NULL, PRIMARY KEY (`location_id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3201 CHARACTER SET = gb2312 COLLATE = gb2312_chinese_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of locations -- ---------------------------- INSERT INTO `locations` VALUES (1000, '1297 Via Cola di Rie', '00989', 'Roma', NULL, 'IT'); INSERT INTO `locations` VALUES (1100, '93091 Calle della Testa', '10934', 'Venice', NULL, 'IT'); INSERT INTO `locations` VALUES (1200, '2017 Shinjuku-ku', '1689', 'Tokyo', 'Tokyo Prefecture', 'JP'); INSERT INTO `locations` VALUES (1300, '9450 Kamiya-cho', '6823', 'Hiroshima', NULL, 'JP'); INSERT INTO `locations` VALUES (1400, '2014 Jabberwocky Rd', '26192', 'Southlake', 'Texas', 'US'); INSERT INTO `locations` VALUES (1500, '2011 Interiors Blvd', '99236', 'South San Francisco', 'California', 'US'); INSERT INTO `locations` VALUES (1600, '2007 Zagora St', '50090', 'South Brunswick', 'New Jersey', 'US'); INSERT INTO `locations` VALUES (1700, '2004 Charade Rd', '98199', 'Seattle', 'Washington', 'US'); INSERT INTO `locations` VALUES (1800, '147 Spadina Ave', 'M5V 2L7', 'Toronto', 'Ontario', 'CA'); INSERT INTO `locations` VALUES (1900, '6092 Boxwood St', 'YSW 9T2', 'Whitehorse', 'Yukon', 'CA'); INSERT INTO `locations` VALUES (2000, '40-5-12 Laogianggen', '190518', 'Beijing', NULL, 'CN'); INSERT INTO `locations` VALUES (2100, '1298 Vileparle (E)', '490231', 'Bombay', 'Maharashtra', 'IN'); INSERT INTO `locations` VALUES (2200, '12-98 Victoria Street', '2901', 'Sydney', 'New South Wales', 'AU'); INSERT INTO `locations` VALUES (2300, '198 Clementi North', '540198', 'Singapore', NULL, 'SG'); INSERT INTO `locations` VALUES (2400, '8204 Arthur St', NULL, 'London', NULL, 'UK'); INSERT INTO `locations` VALUES (2500, 'Magdalen Centre, The Oxford Science Park', 'OX9 9ZB', 'Oxford', 'Oxford', 'UK'); INSERT INTO `locations` VALUES (2600, '9702 Chester Road', '09629850293', 'Stretford', 'Manchester', 'UK'); INSERT INTO `locations` VALUES (2700, 'Schwanthalerstr. 7031', '80925', 'Munich', 'Bavaria', 'DE'); INSERT INTO `locations` VALUES (2800, 'Rua Frei Caneca 1360 ', '01307-002', 'Sao Paulo', 'Sao Paulo', 'BR'); INSERT INTO `locations` VALUES (2900, '20 Rue des Corps-Saints', '1730', 'Geneva', 'Geneve', 'CH'); INSERT INTO `locations` VALUES (3000, 'Murtenstrasse 921', '3095', 'Bern', 'BE', 'CH'); INSERT INTO `locations` VALUES (3100, 'Pieter Breughelstraat 837', '3029SK', 'Utrecht', 'Utrecht', 'NL'); INSERT INTO `locations` VALUES (3200, 'Mariano Escobedo 9991', '11932', 'Mexico City', 'Distrito Federal,', 'MX');
-
创建数据库, 备份数据表用于示例操作:
create database db1; use db1; create table locations as select * from test.locations;
-
编写存储过程批量插入数据:
delimiter // -- 将语句的结束符号从分号;临时改为两个$$(可以是自定义) create procedure add_location_by_batch(cnt int) BEGIN DECLARE i int DEFAULT 0; START TRANSACTION; WHILE i<cnt DO INSERT INTO locations(location_id, street_address, postal_code, city, state_province, country_id) VALUES(3300, '418 Albany Hwy', '0632', 'Auckland', 'North Path',); set i=i 1; end WHILE; COMMIT; END // delimiter; -- 将语句的结束符号恢复为分号
-
调用该存储过程
call add_location_by_batch(10000)
个人对存储过程的态度
做压力测试的时候会用到, 一些ERP系统中会需要使用存储过程, 较老的银行业务会用到, 还是需要会的。
但是将业务逻辑全都写在存储过程中那就是很艹蛋的一种情况了。
-
阿里禁用存储过程的原因:
存储过程没有版本控制,版本迭代的时候要更新很麻烦。
存储过程如果和外部程序结合起来用,更新的时候很难无感升级,可能需要停服。
存储过程不利于将来分库分表。
存储过程可能无法和许多中间件、ORM库一起使用。
-