1449 - The user specified as a definer ('test'@'%') 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_%';

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM