MySQL 存储过程是一组为了完成特定功能的 SQL 语句集,经编译后存储在数据库中,用户通过指定存储过程的名字和参数值来调用它。存储过程可以接收参数,并可以返回结果。存储过程可以看作是对一系列 SQL 操作的封装和重用,它可以提高数据库操作的效率和安全性。
以下是 MySQL 存储过程的基本用法:文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/15384.html
1. 创建存储过程
使用 CREATE PROCEDURE
语句来创建存储过程。语法如下:文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/15384.html
sql
CREATE PROCEDURE procedure_name([parameters])
BEGIN
-- SQL 语句集
END;
其中,procedure_name
是存储过程的名称,parameters
是存储过程的参数列表(可选)(parameters
= [IN|OUT|INOUT] parameter_name data_type, ...
),在 BEGIN
和 END
之间编写要执行的 SQL 语句集。文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/15384.html
例如,创建一个简单的存储过程,用于向表中插入数据:文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/15384.html
sql
DELIMITER //
CREATE PROCEDURE InsertData(IN param1 INT, IN param2 VARCHAR(255))
BEGIN
INSERT INTO your_table_name (column1, column2) VALUES (param1, param2);
END //
DELIMITER ;
注意:DELIMITER
用于改变 MySQL 的命令结束符,因为存储过程内部可能包含多个 SQL 语句,需要使用不同的结束符来区分它们。文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/15384.html
2. 调用存储过程
使用 CALL
语句来调用存储过程。语法如下:文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/15384.html
sql
CALL procedure_name([parameters]);
其中,procedure_name
是存储过程的名称,parameters
是传递给存储过程的参数值(如果有的话)。例如,调用上面创建的 InsertData
存储过程:文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/15384.html
sql
CALL InsertData(1, 'Test');
3. 删除存储过程
- 修改存储过程:MySQL 不直接支持修改存储过程,如果需要修改存储过程,通常的做法是先删除原有的存储过程,然后重新创建。
- 删除存储过程:使用
DROP PROCEDURE
语句来删除存储过程。语法如下:
sql
DROP PROCEDURE IF EXISTS procedure_name;
4. 存储过程的参数
存储过程的参数有三种类型:文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/15384.html
IN
:输入参数,用于传递值给存储过程。存储过程内部可以使用,但不能修改。OUT
:输出参数,用于从存储过程获取值。存储过程内部可以修改,并且在存储过程执行完后可以返回给调用者。INOUT
:既是输入参数也是输出参数。既可以传递值给存储过程,也可以从存储过程获取值。
5. 存储过程的变量
sql
DECLARE variable_name data_type [DEFAULT value];
6. 存储过程的示例
sql
DELIMITER //
CREATE PROCEDURE get_employee(IN emp_id INT)
BEGIN
SELECT * FROM employees WHERE emp_id = emp_id;
END //
DELIMITER;
DELIMITER //
CREATE PROCEDURE add_employee(IN emp_name VARCHAR(255), IN emp_salary INT)
BEGIN
INSERT INTO employees (name, salary) VALUES (emp_name, emp_salary);
END //
DELIMITER;
CALL get_employee(1);
CALL add_employee('John Doe', 5000);
这次写的一个示例,用于删除日志大表中过期的数据:文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/15384.html
sql
CREATE PROCEDURE `delete_expired_log_procedure`(IN __table_name varchar(1000), IN __colume_name varchar(100), IN __id_value bigint, IN __limit int, IN __times int)
BEGIN
# 开始执行时间
DECLARE _start_time DATETIME DEFAULT now();
# 每次删除行数M
DECLARE _row INT DEFAULT __limit;
# 总计删除行数
DECLARE _total_row INT DEFAULT 0;
# 总计删除次数N
DECLARE _times INT DEFAULT 0;
SET @_sql = 'DELETE FROM $TABLE_NAME$ WHERE $COLUME_NAME$ <= $ID_VALUE$ LIMIT $LIMIT$';
SET @_sql = REPLACE(@_sql, '$TABLE_NAME$', __table_name);
SET @_sql = REPLACE(@_sql, '$COLUME_NAME$', __colume_name);
SET @_sql = REPLACE(@_sql, '$ID_VALUE$', __id_value);
SET @_sql = REPLACE(@_sql, '$LIMIT$', __limit);
SET @_remark = concat(@_sql, '; 每次影响行数=');
# 每次删除M行,最多删除N次, 如果有一次删除行数不等于M就退出循环
WHILE _times < __times AND _row = __limit
DO # 每次删除M行
START TRANSACTION;
PREPARE stmt FROM @_sql;
EXECUTE stmt;
# 获取实际删除的行数
SELECT ROW_COUNT() INTO _row;
DEALLOCATE PREPARE stmt;
COMMIT;
SET @_remark = concat(@_remark, _row, ', ');
SET _total_row = _total_row + _row;
SET _times = _times + 1;
END WHILE;
# 保存执行日志
INSERT INTO a_delete_task_log (table_name, delete_row_count, start_time, end_time, create_time, remark)
VALUES (__table_name, _total_row, _start_time, now(), now(), concat('执行次数=', _times, ', sql=', @_remark));
END
用于存储执行记录的表:文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/15384.html
sql
CREATE TABLE `a_delete_task_log` (
`id` bigint NOT NULL AUTO_INCREMENT,
`table_name` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '表名',
`delete_row_count` int NOT NULL DEFAULT '0' COMMENT '删除的记录数',
`start_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务开始时间',
`end_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务结束时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`remark` varchar(500) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '备注',
PRIMARY KEY (`id`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='删除任务日志表';
后续我们是通过一个 MySQL 定时任务 Event 来调度执行的。
7. 存储过程的优点
- 代码重用:存储过程可以被多次调用,提高了代码的重用性。
- 性能优化:存储过程在创建时会被编译并存储在数据库中,减少了 SQL 语句的解析和编译时间,提高了执行效率。
- 事务处理:存储过程可以包含复杂的逻辑和事务处理,确保数据的一致性和完整性。
不过在阿里出的 Java 开发手册里倒是提到了禁止使用存储过程,原文是【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。 不过我在以前的公司也从没使用过存储过程。
评论