1. 程式人生 > >如何在MySQL的儲存過程中書寫批量的使用者許可權/授權語句

如何在MySQL的儲存過程中書寫批量的使用者許可權/授權語句

網上單獨關於MySQL使用者許可權或者儲存過程的文章有不少,但是關於在儲存過程中如何書寫使用者授權語句,尤其是批量授權的資料卻很少。

為什麼筆者會遇到在儲存過程中書寫批量使用者授權語句的需求,是因為筆者在日常開發中承擔了一部分簡單的運維職責(筆者還是很贊同開發兼運維的思想),其中就包括在公司內部機器中搭建MySQL服務。

搭建MySQL服務有一項內容就是配好使用者和許可權管理。筆者不是專職的資料庫運維,在此就舉個自認為還算形象的例子:比如MySQL中會有系統庫(MySQL自帶的,比如mysql、performance_schema等)、測試庫和正式庫,那麼我們可能會劃分出三類MySQL賬號:(1)program賬號:程式用的賬號,能夠對正式或測試庫crud,對系統庫的部分表有select許可權;(2)query賬號:開發者用的賬號,對正式庫或者測試庫都只有select許可權,對系統庫的部分表有select許可權。(3)alpha賬號:開發者用的測試賬號,對測試庫有root許可權(all privileges),對正式庫只有select的許可權,對系統庫的部分表有select許可權。

那麼對於program、query和alpha賬號(以及將來要增加的其他賬號),都會有個共同的需求:指定系統庫的部分表授予select許可權。而這些表的數量不算少,如果每增加一個賬號,就要把所有授權語句依照賬號改一邊再執行一遍,顯得有點麻煩,不如寫個儲存過程,輸入使用者賬號資訊,然後就能把固定需要授予select的許可權語句都執行一遍。

使用者授權語句類似於:

GRANT SELECT ON `mysql`.`time_zone` TO 'query'@'%';

在儲存過程中書寫多個使用者授權語句類似於:

DELIMITER //
CREATE PROCEDURE grantProc()
  BEGIN
    GRANT SELECT ON `performance_schema`.* TO 'query'@'%';
    GRANT SELECT ON `mysql`.`time_zone` TO 'query'@'%';
    GRANT SELECT ON `mysql`.`slow_log` TO 'query'@'%';
    FLUSH PRIVILEGES;
  END
//
DELIMITER ;
CALL grantProc();
DROP PROCEDURE grantProc;

至於儲存過程和授權語句寫法的具體細節大家可以搜尋其他資料,不是本文重點。

可以看到[email protected]部分是重複的,如果能通過儲存過程入參輸入user和host資訊,就不用每次新增賬號都把儲存過程的語句改一遍了。

這裡麻煩的一點是MySQL的授權語句grant to後面的user和host都是要帶單引號的字串(尤其是host部分,user不帶單引號,用字串也是可以的,至少筆者最後可以通過)。

筆者試過幾次,無論是直接傳user和host的字串還是傳入帶轉義單引號的字串,執行時MySQL都報“Error : Can't find any matching row in the user table”錯誤,就是說從mysql.user表裡找不到該host下的user使用者。本質上還是傳參無法直接在grant sql中使用。如下所示:

-- 直接輸入字串
DELIMITER //
CREATE PROCEDURE grantProc(IN inUser varchar(255), IN inHost varchar(255))
  BEGIN
    GRANT SELECT ON `mysql`.`time_zone` TO [email protected];
    FLUSH PRIVILEGES;
  END
//
DELIMITER ;
CALL grantProc('query', '%'); 
DROP PROCEDURE grantProc;
-- 輸入帶轉義單引號字串
DELIMITER //
CREATE PROCEDURE grantProc(IN inUser varchar(255), IN inHost varchar(255))
  BEGIN
    GRANT SELECT ON `mysql`.`time_zone` TO [email protected];
    FLUSH PRIVILEGES;
  END
//
DELIMITER ;
CALL grantProc('\'query\'', '\'%\''); 
DROP PROCEDURE grantProc;

而如果使用concat直接在grant sql中拼接單引號會報語法錯誤,如下所示:

DELIMITER //
CREATE PROCEDURE grantProc(IN inUser varchar(255), IN inHost varchar(255))
  BEGIN
    GRANT SELECT ON `performance_schema`.* TO concat('\'', inUser, '\'')@concat('\'', inHost, '\'');
    FLUSH PRIVILEGES;

  END
//
DELIMITER ;
CALL grantProc('query', '%');
DROP PROCEDURE grantProc;

後來筆者試了用concat拼接的動態SQL配合預編譯和execute才達到目的。直接上最終的儲存過程程式碼(包含了常用的系統庫select許可權授予):

DELIMITER //
CREATE PROCEDURE grantProc(IN inUser varchar(255), IN inHost varchar(255))
  BEGIN
    set @v_user = concat(inUser,'@\'',inHost,'\'');

    set @grand_s= concat('GRANT SELECT ON `performance_schema`.* TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`time_zone` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`slow_log` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`help_keyword` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`time_zone_name` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`event` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`time_zone_transition_type` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`help_relation` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`func` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`proc` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`time_zone_leap_second` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`help_category` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`time_zone_transition` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`general_log` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    set @grand_s= concat('GRANT SELECT ON `mysql`.`help_topic` TO ', @v_user, ';');
    prepare cmd from @grand_s;
    EXECUTE cmd;

    FLUSH PRIVILEGES;

  END
//
DELIMITER ;
CALL grantProc('query', '%');
DROP PROCEDURE grantProc;

有幾點說明:

(1)set, prepare和execute語句重複了很多次,其實可以再寫儲存過程或者函式簡化,只是筆者不願意在這上面再花時間了。目前開發趨勢已經很少用儲存過程了,MySQL這種應該只用於存粹的資料儲存,不負擔任何邏輯才是正道,所以在儲存過程上花時間沒必要。筆者寫這篇文章也只是作為一種筆記。

(2)語句

concat(inUser,'@\'',inHost,'\'');

意思是拼接成[email protected]'%'的字串。user沒有用單引號拼接,最後也能執行成功,但是host如果不加單引號會包語法錯誤。sql中轉義用的是反斜槓\。

(3)授權語句執行完畢後想要生效最後必須加上:FLUSH PRIVILEGES。

(4)儲存過程現在已經不常用了,執行完畢 最後drop掉吧,免得留坑。

相關推薦

如何在MySQL儲存過程書寫批量的使用者許可權/授權語句

網上單獨關於MySQL使用者許可權或者儲存過程的文章有不少,但是關於在儲存過程中如何書寫使用者授權語句,尤其是批量授權的資料卻很少。 為什麼筆者會遇到在儲存過程中書寫批量使用者授權語句的需求,是因為筆者在日常開發中承擔了一部分簡單的運維職責(筆者還是很贊同開發兼運維的思想)

MySql儲存過程傳參和不傳參以及java呼叫程式碼

資料庫表結構 1.mysql不傳參寫儲存過程 create procedure product() -- product為儲存過程名稱 begin select * from book; end 呼叫此儲存過程為 CALL product

MySQL儲存過程的3種迴圈,儲存過程的基本語法,ORACLE與MYSQL儲存過程/函式的使用區別,退出儲存過程方法

  學無止境 部落格園   首頁   新隨筆   聯絡   訂閱  管理 隨筆-1968  評論-103  文章-4&

MySQL 儲存過程執行DDL

一、定期增加表分割槽 1、增加表分割槽例 CREATE DEFINER=`root`@`127.0.0.1` PROCEDURE `p_create_Partition`(IN databaseName VARCHAR(50),IN tableName VARCHAR(50))L_END:BEGIN&nb

MySQL儲存過程declare和set定義變數的區別

  在儲存過程中常看到declare定義的變數和@set定義的變數。簡單的來說,declare定義的類似是區域性變數,@set定義的類似全域性變數。  1、declare定義的變數類似java類中的區域性變數,僅在類中生效。即只在儲存過程中的begin和end之間生效。  2

mysql儲存過程使用select count(*) into 變數名 from +表+ where條件的用法

select count(*) into v_count from dual where userid=2;此語句的意思就是根據where條件查詢dual表,得到的行數存入變數v_count中(給變數賦值) 只能在儲存過程中編寫這樣的語句?如果在mysql的sql語句中編寫

mysql儲存過程 declare 和 set 定義變數的區別

mysql儲存過程中,定義變數有兩種方式: 1.使用set或select直接賦值,變數名以 @ 開頭. 例如:set @var=1; 可以在一個會話的任何地方宣告,作用域是整個會話,稱為會話變數。 2.以 DECLARE 關鍵字宣告的變數,只能在儲存過程中使用,稱為儲存過

Mysql儲存過程字串分割

今在專案中碰到了要把字串分割,記錄下來,以後可能還用的到 首先想上我的儲存過程程式碼 DELIMITER $$ USE `bplate`$$ DROP PROCEDURE IF EXISTS `lp_plate_insertplateinfo`$$ CREATE DE

mysql 儲存過程limit

1、mysql的高版本(5.5),儲存過程中的limit可以使用變數,如下:select * from student limit iStart,iNum; 2、mysql的低版本(5.1),儲存過程中的limit不能使用變數,編譯報錯,如下:You have an error in your SQL sy

mysql 儲存過程使用多遊標

mysql的儲存過程可以很方便使用遊標來實現一些功能,儲存過程的寫法大致如下: 先建立一張表,插入一些測試資料: DROP TABLE IF EXISTS netingcn_proc_test; CREATE TABLE `netingcn_proc_test`

MySQL儲存過程的三種迴圈方式

“明月別枝驚鵲,清風半夜鳴蟬” 最近儲存過程寫得多,迴圈多數用在遊標裡,在這裡總結幾種迴圈的方式 CREATE DEFINER=`root`@`localhost` PROCEDURE `NewProc`() BEGIN DECLARE sta

mysql儲存過程的三種迴圈

#loop drop procedure if exists p1_; create procedure p1_ ( in in_ int , out out_ varchar(3)) #varch

mysql儲存過程、檢視等的許可權問題

看儲存過程定義,DELIMITER $$ CREATE /*[DEFINER = { user | CURRENT_USER }]*/ PROCEDURE `DB_U1`.`P1`() /*LANGUAGE SQL | [NOT] DETE

MySQL儲存過程的IN,OUT,INOUT型別 用法

MySQL儲存過程中有IN,OUT,INOUT型別 ----------------------------------- ## IN IN引數只用來向過程傳遞資訊,為預設值。 ## MySQL儲存過程"in"引數:跟C語言的函式引數的值傳遞類似,MySQL儲存過程內部

MySQL儲存過程的3種迴圈

    -> begin    -> declare i int default 0;    -> loop_label:loop    ->     if i=3 then    ->         set i=i+1;    ->         iterate lo

MySql儲存過程limit傳參

最近做專案用到了MySql資料庫,感覺還是蠻好用的,但是有同事前幾天寫儲存過程的時候老調不通,我看了看後發現把limit語句後面帶的引數隨便改成一個數字就除錯通過了,不知道是MySql當初就這麼設計的還是一個bug。後來在網上找到一個方法可以通過傳引數的方法解決該問題:

Mysql儲存過程使用cursor

一、表 學生表 CREATE TABLE `t_student` (    `stuNum` int(11) NOT NULL auto_increment,    `stuName` varchar(20) default NULL,    `birthday` date default NULL,    

MySql儲存過程的基本函式和需要用到的運算子

mysql儲存過程學習總結-操作符算術運算子+ 加 SET var1=2+2; 4- 減 SET var2=3-2; 1* 乘 SET var3=3*2; 6/ 除 SET var4=10/3; 3.3333DIV 整除 SET var5=10 DIV 3; 3% 取模 SET var6=10%3 ; 1比較

MySQL儲存過程,定義變數有兩種方式

MySQL儲存過程中,定義變數有兩種方式: 1.使用set或select直接賦值,變數名以 @ 開頭. 例如:set @var=1; 可以在一個會話的任何地方宣告,作用域是整個會話,稱為會話變數。

JDBC連線執行MySQL儲存過程報空指標或許可權錯誤

 最近使用root使用者編寫了幾個儲存過程,但是使用普通使用者通過JDBC連線執行卻報錯: java.lang.NullPointerException...... 或 java.sql.SQLException: User does not have access to m