1. 存储函数
(1). 语法格式 :
DELIMITER // CREATE FUNCTION 函数名(参数名 参数类型,...) RETURNS 返回值类型 [characteristics ...] BEGIN 函数体 #函数体中肯定有 RETURN语句 END // DELIMITER ;
(2). 说明 :
- 参数列表 : 在存储函数FUNCTION中的参数列表中,总是默认为IN参数.
- 必须指明RETURNS 返回值的类型.RETURNS子句只能对FUNCTION做限定,对函数而言是强制性的.用来指定函数的返回值类型.因为函数的函数体必须包含以一个RETURN子句返回一个值.
- characteristic创建函数时指定的对函数的约束.其与存储过程类似.
- 由于存储函数一定会返回一个值,所以调用存储函数的格式为SELECT 函数名(实参列表).
2. 创建存储函数
例1 :
- 创建存储函数,必须添加characteristic约束,不然会报错.
- 存储函数的函数体必有RETURN语句.
例2 :
3. 对比存储函数与存储过程
(1). 关键字
- 存储过程 : PROCEDURE.
- 存储函数 : FUNCTION.
(2). 调用语法
- CALL存储过程.
- SELECT 存储函数.
(3). 返回值
- 理解为0个或多个.
- 只能是一个值.
(4). 应用场景
- 一般用于更新.
- 一般用于查询结果为一个值并返回.
存储函数可以放在查询语句中,而存储过程不可以.但存储过程的功能显然更加强大,包括能够执行对表的操作和事务操作,这是存储函数不具备的.
4. 存储过程/函数的查看与修改
(1). 查看
(1). 方式1 :
SHOW CREATE FUNCTION count_by_id;
(2). 方式2 :
SHOW FUNCTION STATUS LIKE 'count_by_id';
(3). 方式3:
MySQL中存储过程和函数的信息存储在information_schema数据库下的Routines表中。可以通过查询该表的记录来查询存储过程和函数的信息
SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME='count_by_id' AND ROUTINE_TYPE = 'FUNCTION';
(2). 修改
修改存储过程或函数,不影响其功能,只是修改其特性.
ALTER {PROCEDURE | FUNCTION} 存储过程或函数的名 [characteristic ...]
(3). 删除
可以删除存储过程或存储函数,使用DROP子句完成.
DROP FUNCTION count_by_id1;
5. 存储函数的优劣
(1). 优点
- 存储过程可以一次编译多次使用 : 存储过程只在创建时进行编译,之后的使用都不需要重新编译,这就提升了 SQL 的执行效率。
- 可以减少开发工作量 : 将代码 封装 成模块,实际上是编程的核心思想之一,这样可以把复杂的问题拆解成不同的模块,然后模块之间可以 重复使用 ,在减少开发工作量的同时,还能保证代码的结构清晰。
- 存储过程的安全性强 : 我们设定存储过程的时候可以 设置对用户的使用权限 ,这样就和视图一样具有较强的安全性。
- 可以减少网络传输量 : 因为代码封装到存储过程中,每次使用只需要调用存储过程即可,这样就减少了网络传输量。
- 良好的封装性 : 在进行相对复杂的数据库操作时,原本需要使用一条一条的 SQL 语句,可能要连接多次数据库才能完成的操作,现在变成了一次存储过程,只需要 连接一次即可 。
(2). 缺点
- 可移植性差 : 存储过程不能跨数据库移植,比如在 MySQL、Oracle 和 SQL Server 里编写的存储过程,在换成其他数据库时都需要重新编写。
- 调试困难 : 只有少数 DBMS 支持存储过程的调试。对于复杂的存储过程来说,开发和维护都不容易。虽然也有一些第三方工具可以对存储过程进行调试,但要收费。
- 存储过程的版本管理很困难 : 比如数据表索引发生变化了,可能会导致存储过程失效。我们在开发软件的时候往往需要进行版本管理,但是存储过程本身没有版本控制,版本迭代更新的时候很麻烦。
- 它不适合高并发的场景 : 高并发的场景需要减少数据库的压力,有时数据库会采用分库分表的方式,而且对可扩展性要求很高,在这种情况下,存储过程会变得难以维护, 增加数据库的压力 ,显然就不适用了。