在 MySQL 数据库中,在创建视图及函数的时候,通常会用到definer。并且在迁移视图或函数过程中,该选项经常会引起报错。本篇文章主要介绍下 MySQL 中 definer 的含义及作用。
1. DEFINER简单介绍
下述是创建视图的基础语法
CREATE[OR REPLACE][ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}][DEFINER = user][SQL SECURITY { DEFINER | INVOKER }]VIEW view_name [(column_list)]AS select_statement[WITH [CASCADED | LOCAL] CHECK OPTION]
在上述SQL中,definer出现了两次。一次是 DEFINER = user,该语句表明该视图的定义者是user
用户,若不显式指定,则创建此对象的用户就是定义者;另一次是SQL SECURITY 选项,该选项可以设置为 DEFINER 或 INVOKER。其中,当SQL SECURITY为DEFINER时,表示
执行该视图(函数/存储过程),需要使用DEFINER的权限来执行,如果DEFINER没有权限,则执行不成功。当 SQL SECURITY 属性为 INVOKER 时,则需要执行者有调用权限并且有引用的相关对象的权限(即表的增删改查等权限),才能成功执行。
2. 实验验证
以SQL SECURITY为DEFINER为例
#使用root账号操作
#1.本地可用账号test
create user `test`@`localhost` identified by ‘123456’ #2.创建存储过程
CREATE DEFINER=`test`@`localhost` PROCEDURE mytest() SQL SECURITY DEFINER
BEGIN
SELECT * FROM test.`user`;
END ##3.执行存储过程
CALL mytest();显示:execute command denied to user 'test'@localhost' for routine 'test.mytest;#4.赋予test用户mytest存储过程的执行权限
GRANT EXECUTE on PROCEDURE test.mytest to `test`@`localhost`;#5.执行存储过程
CALL mytest();显示:SELECT command denied to user 'test'@'localhost' for table 'user#6.赋予test账号test数据库所有表的select权限
GRANT SELECT ON test.* TO `test`@`localhost`;显示:正常
以SQL SECURITY为INVOKER为例
#使用root账号操作
#1.本地可用账号test
create user `test`@`localhost` identified by ‘123456’ #2.创建存储过程
CREATE DEFINER=`test`@`localhost` PROCEDURE mytest() SQL SECURITY INVOKER
BEGIN
SELECT * FROM test.`user`;
END ##3.执行存储过程
CALL mytest();显示:execute command denied to user 'test'@localhost' for routine 'test.mytest;#4.赋予test用户mytest存储过程的执行权限
GRANT EXECUTE on PROCEDURE test.mytest to `test`@`localhost`;#5.执行存储过程
CALL mytest();显示:正常
3. 一些注意事项
额外补充点知识,只有拥有创建权限且有 SUPER 权限的用户才可以建 DEFINER = 其他用户的对象。例如:root 账号可以创建 DEFINER = testuser 的视图,而 testuser 在有创建视图的前提下只能创建 DEFINER 为自己的视图。
为了更细致的了解 DEFINER 相关作用,以视图为例再来说几个特殊情况下的示例:
假设用户 u1 不存在,使用 root 账号可以创建 DEFINER = u1 的视图,若该视图的 SQL SECURITY 属性为 DEFINER ,则查询时会报用户不存在的错误,若该视图的 SQL SECURITY 属性为 INVOKER ,则使用 root 账号可正常查询该视图。
假设用户 u2 存在但不具有查询表 a 的权限,使用 root 账号可以创建 DEFINER = u2 的视图来查询表 a ,若该视图的 SQL SECURITY 属性为 DEFINER ,则查询时报缺少权限的错误,若该视图的 SQL SECURITY 属性为 INVOKER ,则使用 root 账号可正常查询该视图。当使用用户 u2 登录时,则创建视图来查询表 a 会直接报错缺少权限,即创建不了查询表 a 的视图,无论此视图的 SQL SECURITY 属性是什么。
看完上述示例后,不清楚你对 DEFINER 是否有了更清晰的认识,有兴趣的同学可以自己测试看一看。结合笔者日常经验,说下 DEFINER 相关注意事项吧:
- SQL SECURITY 属性建议使用默认的 DEFINER 。
- 某个库内的视图、函数、存储过程建议使用统一的 DEFINER 用户。
- 不要轻易修改及删除数据库用户,因为此用户可能是相关对象的定义者。
- 若要修改 SQL SECURITY 属性,请做好测试,清楚修改前后的区别。
- 数据库迁移时,要注意新环境存在相关对象的定义者用户。
- 做数据库迁移时,建议首先在新环境创建相关用户及赋予权限。
4. 参考链接
- MySQL DEFINER详解 - MySQL技术 - 博客园 (cnblogs.com)