zoukankan      html  css  js  c++  java
  • [mysql]The user specified as a definer ('XXXXXX'@'%') does not exist

    最近在做一个项目,由于服务器切换,所以需要将原有服务器的mysql数据表以及存储过程导入到另一个服务器的mysql数据库中。导入完成之后以为一切是那么的简单,却没有想到总还是出现了一些莫名其妙的问题。

    我在用程序调用存储过程时,总是提示错误:

    1 The user specified as a definer ('test'@'%') does not exist 1449

    查看了自己mysql的用户表后,发现确实没有test这个用户,但是我程序用的是root登录的,所以感觉有些莫名其妙。

    后来通过查资料发现,是由于自己存储过程设置的安全性为definer,而当时的那个数据库存在test这个用户且用的test用户创建的存储过程。

    所以解决方法主要有以下两种:

    保持definer安全性

    1)在navicat上进行修改

    将定义者从test改为在该服务器存在的用户(一般每个服务器都有root@localhost)

    2)通过sql语句修改

    1 mysql>update mysql.proc set DEFINER='root@localhost' WHERE NAME='' AND db='mydb';

    其中,mysql.proc是固定的,definer即要改为的用户名,name为存储过程名,db为数据库名

    将安全性修改为invoker

    1)在navicat上进行修改

    2)通过sql语句进行修改

    1 ALTER PROCEDURE proc_name SQL SECURITY INVOKER 
    2 ALTER PROCEDURE proc_name SQL SECURITY DEFINER

    引申阅读:mysql存储过程的definer和invoker

    【用户操作存储过程的权限】

    1 ALTER ROUTINE -- 编辑或删除存储过程
    2 
    3 CREATE ROUTINE -- 创建存储过程
    4 
    5 EXECUTE          -- 运行存储过程

    【存储过程的创建语法】

    复制代码
     1 delimiter //    -- 声明分隔符(命令结束符)
     2 
     3 create 
     4 
     5  definer = user@hostname | current_user 
     6 
     7  procedure 存储过程名 (参数)
     8 
     9  comment '注释'
    10 
    11  sql security definer | invoker   -- sql 的安全设置
    12 
    13 begin
    14 
    15   存储过程的body
    16 
    17 end
    18 
    19 //
    20 
    21 delimiter ;    -- 声明分隔符(命令结束符)
    复制代码

    【函数的创建语句】

    复制代码
     1 delimiter //    -- 声明分隔符(命令结束符)
     2 
     3 create
     4 
     5  definer = user@hostname | current_user
     6 
     7  function 函数名(参数)
     8 
     9  return 返回值类型
    10 
    11  comment '注释'
    12 
    13  sql security definer | invoker   -- sql 的安全设置
    14 
    15 begin
    16 
    17   函数的body
    18 
    19 end
    20 //
    21 
    22 delimiter ;    -- 声明分隔符(命令结束符)
    复制代码

    【definer和invoker的解释】

       创建存储过程的时候可以指定 SQL SECURITY属性,设置为 DEFINER 或者INVOKER,用来告诉mysql在执行存储过程的时候,是以DEFINER用户的权限来执行,还是以调用者的权限来执行。

       默认情况下,使用DEFINER方式,此时调用存储过程的用户必须有存储过程的EXECUTE权限,并且DEFINER指定的用户必须是在mysql.user表中存在的用户。

       DEFINER模式下,默认DEFINER=CURRENT_USER,在存储过程执行时,mysql会检查DEFINER定义的用户'user_name'@'host_name'的权限;

       INVOKER模式下,在存储过程执行时,会检查存储过程调用者的权限。

      如果SQL SECURITY子句指定为DEFINER,存储过程将使用存储过程的DEFINER执行存储过程,验证调用存储过程的用户是否具有存储过程的execute权限和DEFINER用户是否具有存储过程引用的相关对象的权限;
      如果SQL SECURITY子句指定为INVOKER,那么MySQL将使用当前调用存储过程的用户执行此过程,并验证用户是否具有存储过程的execute权限和存储过程引用的相关对象的权限;

      案例一:DEFINER

    1 CREATE DEFINER = 'admin'@'localhost' PROCEDURE account_count()
    2    BEGIN
    3        SELECT 'Number of accounts:', COUNT(*) FROM mysql.user;
    4    END;

       在这个案例中,不论哪个用户A调用存储过程,存储过程都会以'admin'@'localhost'的权限去执行,即使这个用户A没有查询mysql.user表的权限。

     案例二:INVOKER

    1 CREATE DEFINER = 'admin'@'localhost' PROCEDURE account_count()
    2        SQL SECURITY INVOKER
    3    BEGIN
    4        SELECT 'Number of accounts:', COUNT(*) FROM mysql.user;
    5    END;

       在这个案例中,虽然存储过程语句中仍然带有DEFINER参数,但是由于SQL SECURITY指定了INVOKER,所以在存储过程执行的时候,会以调用者的额身份去执行。此时这个存储过程是否能成功执行,取决于调用者是否有mysql.user表的查询权限。

    【案例】

    案例一:调用存储过程

     存储过程的调用者是   : admin@192.168.1.1

     存储过程的DEFINER是   : admin@%

     MySQL中存在的用户是 : admin@192.168.%.%

       此时admin@192.168.1.1是可以访问数据库的,因为它符合admin@192.168.%.%的授权规则,但是当它调用DEFINER='admin@%'的存储过程的时候,mysql会检查mysql.user用户表中是否存在admin@%这个用户,mysql的检查结果是admin@%这个用户不存在,此时就会返回报错,提示“Ther user specified as a definer ('admin@%') does not exist.。

    案例二:创建存储过程

     使用用户admin@192.168.1.1连接mysql,该用户有test库的all privileges,执行创建存储过程的操作:

             存储过程中定义的DEFINER是    : admin@%

             MySQL中存在的用户是     : admin@192.168.%.%

     此时,会遇到报错,提示”ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER privilege(s) for this operation“

     修复DEFINER='admin@192.168.%.%',或者去掉 DEFINER参数,都可以恢复正常。

    说明:

       案例一中是存在问题的,存储过程的调用者和拥有者都是admin@192.168.1.1,但是DEFINER却是admin@%,这是由于创建存储过程的命令是由root用户执行的,所以没有遇到案例二中的报错。

    【存储过程常用命令】

    复制代码
     1 -- 查看存储过程的创建语句:
     2 
     3 show create procedure 存储过程名;
     4 
     5 -- 查看存储过程的信息:
     6 
     7 show procedure status like '存储过程名'G
     8 
     9 -- 查看存储过程的Definer信息:
    10 
    11 select db,name,type,sql_security,definer from mysql.proc where  type='PROCEDURE' and db='数据库名' ;
    12 
    13 -- 修改存储过程的DEFINER:
    14 
    15 update  mysql.proc  set `definer` ='admin@192.168.%.%' where db like 'db_%';
    复制代码
  • 相关阅读:
    qt捕鱼达人
    linux通过源码安装gdb
    打造简易http服务器
    linux缓存同步
    NOI之后的碎碎念
    Validate至少有一个不能为空
    IOI 2020 集训队作业
    P6033 [NOIP2004 提高组] 合并果子 加强版 题解
    P3017 [USACO11MAR]Brownie Slicing G 题解
    LOJ #145. DFS 序 2 题解
  • 原文地址:https://www.cnblogs.com/ianlab/p/14025888.html
Copyright © 2011-2022 走看看