違背常識,MySQL使用Grant授權(quán)后沒必要Flush Privilege
從我上大學(xué)時,數(shù)據(jù)庫概論老師就告訴我,MySQL使用grant對用戶授權(quán)之后,一定記得要用flush privilege命令刷新緩存,這樣才能使賦權(quán)命令生效。畢業(yè)工作以后,在很多的技術(shù)文檔上,仍然可以看到這種解釋。
但是,grant授權(quán)之后真的必須flush privilege嗎?如果不flush,授權(quán)真的就不生效嗎?
本篇文章也許會顛覆你的認知。
grant語句都做了哪些事
grant語句一般和創(chuàng)建用戶配合使用,比如創(chuàng)建一個用戶之后,給這個用戶授予一定的權(quán)限,當然,也可以對一個已存在的用戶授權(quán)。
我們以新建一個用戶testuser為例:
這條語句會往mysql.user表插入一行數(shù)據(jù),同時會往內(nèi)存中一個叫acl_users的數(shù)組中插入一個acl_user對象。
由于還沒有對這個用戶授權(quán),所以這個用戶在user表中權(quán)限字段都是N,在acl_users數(shù)組中的對象的access字段都是0,表示還沒有任何權(quán)限。
而對于一個用戶的權(quán)限來說,其范圍是不同的,分別為全局權(quán)限、DB權(quán)限、表權(quán)限、列權(quán)限。
全局權(quán)限
當我們對一個用戶授予全局權(quán)限后,這個用戶就擁有了對整個數(shù)據(jù)庫實例的權(quán)限。
對testuser授予全局權(quán)限的寫法:
使用grant授權(quán)之后,mysql.user表中testuser這一行的權(quán)限字段的值就會全部變成Y,內(nèi)存中access的值也會變成1。
這時,如果有新的數(shù)據(jù)庫鏈接接入,就可以從acl_users數(shù)組中查到這個用戶的權(quán)限,并且保存在當前的線程對象。
總結(jié)一下就是,grant命令同時更新了磁盤和內(nèi)存的值,并且對于新鏈接會立刻生效,但是對于已經(jīng)存在的老的鏈接,則不會產(chǎn)生影響。
大家可以思考一下,為什么對于老的鏈接,grant命令不會立刻生效。
DB權(quán)限
DB權(quán)限就是給一個用戶單獨指定某個庫的所有權(quán)。
DB權(quán)限與全局權(quán)限的授權(quán)命令的區(qū)別在于指定了DB庫:db1.*,而不是*.*。
執(zhí)行g(shù)rant命令之后,MySQL會往mysql.db表插入一條記錄,并且把權(quán)限字段的值置為Y,
另外增加一個對象到內(nèi)存中的acl_dbs中,access的值設(shè)置為1。
當MySQL判斷一個用戶對某個數(shù)據(jù)庫的執(zhí)行權(quán)限時,會遍歷這個acl_dbs數(shù)組,根據(jù)當前的user、host地址、DB名匹配符合的記錄,并判斷其中的權(quán)限位。
DB權(quán)限和全局權(quán)限的不同點在于,全局權(quán)限查詢后會設(shè)置到當前鏈接的線程對象中,每次判斷權(quán)限只需從線程對象中獲取判斷即可,而判斷DB權(quán)限需要每次遍歷acl_dbs數(shù)組。
由于每次判斷DB權(quán)限都需要去內(nèi)存中遍歷acl_dbs數(shù)組,而這個數(shù)組又是一個全局對象,所以使用grant操作DB權(quán)限后,會立刻對所有鏈接生效。
表權(quán)限和列權(quán)限
除了全局權(quán)限和DB權(quán)限,MySQL還支持我們定義粒度更細的表權(quán)限和列權(quán)限。
grant表權(quán)限時,MySQL會更新mysql.tables_priv表,
grant列權(quán)限時,MySQL會更新mysql.columns_priv表,
同時,這兩個操作都會觸發(fā)MySQL更新內(nèi)存中的hash表column_priv_hash。
?與DB權(quán)限一樣,對于表權(quán)限和列權(quán)限的修改,也會立刻影響到所有的鏈接。
那說了這么多,看起來grant命令都是立刻生效了,好像也不需要執(zhí)行flush privileges了?
其實答案就是這樣的,grant命令授權(quán)后,并不需要再特意執(zhí)行flush privileges了。
flush privileges的使用場景
既然MySQL提供了flush privileges,說明肯定有其適用的場景。
那么,flush privileges一般用在什么場景呢?
當使用flush privileges時,會清空內(nèi)存中的acl_users、acl_dbs等數(shù)組,然后從表mysql.users、mysql.db等表中重新加載數(shù)據(jù),
?換句話說,flush privileges主要用于使內(nèi)存中的權(quán)限和數(shù)據(jù)庫中保持一致。
一般來說,內(nèi)存中的數(shù)據(jù)和磁盤表中的數(shù)據(jù)都是一致的,但是當我們直接使用DML語句修改權(quán)限表中的值時,就會造成內(nèi)存和磁盤的數(shù)據(jù)不一致。
這時,就需要使用flush privileges命令,刷新內(nèi)存,使內(nèi)存和磁盤的數(shù)據(jù)保持一致。
總結(jié)
使用grant命令之后,并不需要再隨手加上flush privileges,因為grant 語句會同時修改數(shù)據(jù)表和內(nèi)存。
只有當我們不規(guī)范的直接使用DML語句修改表中權(quán)限字段時,才需要使用flush privileges刷新數(shù)據(jù)。