如何在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