创建视图和函数,你注意到Definer是什么意思了吗?转载本文请联系MySQL技术公众号。前言:在MySQL数据库中,创建视图和函数时,你有没有注意过definer选项?迁移view或function后是否报错,这些其实可能跟definer有关。本文主要介绍MySQL中definer的含义和作用。一、DEFINER简介以视图为例,看一下官方创建视图的语法:CREATE[ORREPLACE][ALGORITHM={UNDEFINED|MERGE|TEMPTABLE}][DEFINER=user][SQLSECURITY{DEFINER|INVOKER}]VIEWview_name[(column_list)]ASselect_statement[WITH[CASCADED|LOCAL]CHECKOPTION]仔细看上面的语法,发现definer出现了两次,一次是DEFINER=user,一次是SQLSECURITY。该选项可以设置为DEFINER或INVOKER,看到这里,你猜到definer的作用了吗?Definer翻译成中文就是“定义者”的意思。在MySQL中,在创建视图(views)、函数(functions)、存储过程(procedures)、触发器(triggers)、事件(events)时,可以指定DEFINER=user选项,即谁是这个的定义者目的。除非明确指定,否则创建此对象的用户就是定义者。对于视图、函数和存储过程,还可以指定SQLSECURITY属性,其值可以是DEFINER(定义者)或INVOKER(调用者),表示在执行过程中使用谁的权限来执行。DEFINER表示按照定义者的权限执行,INVOKER表示按照调用者的权限执行。默认情况下,SQLSECURITY属性是DEFINER。当其值为DEFINER时,DEFINER指定的定义者用户必须存在于数据库中,并且定义者用户具有相应的操作权限和引用相关对象的权限。执行者只需要有调用权限就可以执行成功。当SQLSECURITY属性为INVOKER时,执行者需要有调用权限和引用相关对象的权限才能成功执行。简单的说,假设一个视图查询三个表abc,如果这个视图的SQLSECURITY属性是DEFINER,当使用用户u查询这个视图时,用户u只需要这个视图的查询权限即可;如果这个视图的SQLSECURITY属性是如果SECURITY属性是INVOKER,用户u需要有这个视图的查询权限和abc这三个表的查询权限。下面通过例子具体演示:#创建两个都是testuser的viewdefiner,查询test_tb表mysql>showgrantsfor'testuser'@'%';+------------------------------------------------------------------------------------------------------+|Grantsfortestuser@%|+---------------------------------------------------------------------------------------------------+|GRANTUSAGEON*.*TO'testuser'@'%'||GRANTSELECT,INSERT,UPDATE,DELETE,CREATE,CREATEVIEW,SHOWVIEWON`testdb`.*TO'testuser'@'%'|+--------------------------------------------------------------------------------------------------+2rowsinset(0.00sec)mysql>showcreateviewview_definer\G*******************************1.row******************************视图:view_definerCreateView:CREATEALGORITHM=UNDEFINEDDEFINER=`testuser`@`%`SQLSECURITYDEFINERVIEW`view_definer`ASselect`test_tb`.`stu_id`AS`stu_id`,`test_tb`.`stu_name`AS`stu_name`from`test_tb`character_set_client:utf8mb4collat??ion_connection:utf8mb4_general_ci1rowinset(0.00sec)mysql>showcreateviewview_invoker\G******************************1.row********************************视图:view_invokerCreateView:CREATEALGORITHM=UNDEFINEDDEFINER=`testuser`@`%`SQLSECURITYINVOKERVIEW`view_invoker`ASselect`test_tb`.`stu_id`AS`stu_id`,`test_tb`。`stu_name`AS`stu_name`from`test_tb`character_set_client:utf8mb4collat??ion_connection:utf8mb4_general_ci1rowinset(0.00sec)#只赋予uview用户查询这两个视图的权限,用于查询测试mysql>selectuser();+------------------+|user()|+----------------+|uview@localhost|+----------------+1rowinset(0.00sec)mysql>showgrants;+--------------------------------------------------------+|Grantsforuview@%|+---------------------------------------------------+|GRANTUSAGEON*.*TO'uview'@'%'||GRANTSELECTON`testdb`.`view_definer`TO'uview'@'%'||GRANTSELECTON`testdb`.`view_invoker`TO'uview'@'%'|+----------------------------------------------------+3rowsinset(0.00sec)mysql>选择*fromview_definer;+------+----------+|stu_id|stu_name|+------+----------+|1001|来自1||1002|dfsfd||1003|fdgfg|+--------+----------+9rowsinset(0.00sec)mysql>select*fromview_invoker;ERROR1356(HY000):View'testdb。view_invoker'referencesinvalidtable(s)orcolumn(s)orfunction(s)ordefiner/invokerofviewlackrightstousethem#结果是view_definer查询正常,但是无法查询到view_invoker,因为uview用户没有test_tb表的查询权限。自定义函数和存储过程也类似,如果SQL的SECURITY属性是INVOKER,调用者也需要有执行权限和引用相关对象的权限才能执行成功。2.一些注意事项补充知识。只有具有创建权限和SUPER权限的用户才能创建DEFINER=otherUser对象。例如:root账户可以创建DEFINER=testuser视图,但是testuser只能在创建视图的前提下创建DEFINER作为自己的视图。为了更详细的了解DEFINER的相关功能,以视图为例,给出一些特殊情况的例子:假设用户u1不存在,使用root账户创建一个DEFINER=u1的视图,如果SQL视图的SECURITY属性为DEFINER,查询时会报用户不存在的错误。如果视图的SQLSECURITY属性为INVOKER,则可以使用root账号正常查询视图。假设用户u2存在但没有查询a表的权限,使用root账号创建一个DEFINER=u2的视图来查询a表。如果视图的SQLSECURITY属性是DEFINER,查询会报缺少权限的错误。如果视图的SQLSECURITY属性为INVOKER,则可以使用root帐户正常查询视图。使用用户u2登录时,创建查询a表的视图会直接报权限不足,即无法创建查询a表的视图,不管这个视图的SQLSECURITY属性是什么。看完上面的例子,不知道大家是不是对DEFINER有了更清晰的认识。感兴趣的同学可以自行测试。下面结合笔者的日常经验,说说DEFINER相关的注意事项:SQLSECURITY属性建议使用默认的DEFINER。建议对某个库中的视图、函数、存储过程使用统一的DEFINER用户。不要轻易修改或删除数据库用户,因为该用户可能是相关对象的定义者。如果要修改SQLSECURITY属性,请测试一下修改前后的区别。迁移数据库时,注意新环境中相关对象的定义者用户。在进行数据库迁移时,建议先在新环境中创建相关用户并授予权限。总结:本文主要介绍DEFINER的相关知识,DEFINER主要是在创建视图、函数、存储过程等对象时遇到的,通常容易被忽略。但这些细节还是要注意的。多学多学,这样在实际使用的时候就可以避免很多错误。
