当前位置: 首页 > 科技观察

与常识相反,MySQL使用Grant授权后就不需要FlushPrivilege

时间:2023-03-20 18:26:32 科技观察

了。从大学开始,数据库介绍老师就告诉我,MySQL使用grant授权用户后,一定要记得使用flushprivilege命令刷新缓存,这样grantpowerorder才会生效。毕业后,在很多技术文档中仍然可以看到这种解释。但是,授予授权后是否真的需要刷新权限?如果不flush,授权真的不会生效吗?这篇文章可能会颠覆你的认知。授权声明有什么作用?grant语句通常与创建用户结合使用。例如,创建用户后,授予用户一定的权限。当然,它也可以授权现有用户。以新建用户testuser为例:创建用户'testuser'@'%'identifiedby'pwd';这条语句会向mysql.user表中插入一行数据,同时向内存中的acl_user对象中一个名为acl_users的数组中插入一行。由于这个用户还没有被授权,所以这个用户在user表中的权限字段都是N,而acl_users数组中对象的access字段都是0,说明还没有权限。对于一个用户的权限,范围是不同的,分别是全局权限、DB权限、表权限、列权限。全局权限当我们授予一个用户全局权限时,该用户就拥有了对整个数据库实例的权限。给testuser授予全局权限的写法:grantoption将*.*的所有权限授予'testuser'@'%';使用grant授权后,mysql.user表中testuser行的permission字段的值都会变成Y,内存中的access的值也会变成1。此时如果有新的数据库连接access,从acl_users数组中可以查到用户的权限,保存在当前线程对象中。综上所述,grant命令同时更新磁盘和内存值,对于新链接会立即生效,但不会影响已有的旧链接。大家可以想想为什么旧链接的grant命令没有立即生效。DB权限DB权限是为一个用户单独指定一个库的所有权。使用授予选项将db1.*上的所有权限授予'testuser'@'%';DB权限授权命令和全局权限授权命令的区别在于指定的是DB库:db1.*而不是*.*。执行完grant命令后,MySQL会在mysql.db表中插入一条记录,并将permission字段的值设置为Y,并在内存中的acl_dbs中添加一个对象,并将access的值设置为1。当MySQL判断用户对某个数据库的执行权限,遍历acl_dbs数组,根据当前用户、主机地址、DB名匹配匹配的记录,判断其中的权限位。DB权限和全局权限的区别在于查询到全局权限后,会设置为当前链接的线程对象,每次判断权限只需要从线程对象中获取,而判断DB权限需要遍历acl_dbs每次都是数组。因为每次判断DB权限,都需要遍历内存中的acl_dbs数组,而这个数组是一个全局对象,所以使用grant操作DB权限后,会立即对所有链接生效。表权限和列权限除了全局权限和DB权限,MySQL还支持我们定义更细粒度的表权限和列权限。使用授予选项将db1.table1上的所有权限授予'testuser'@'%';grantSELECT(id)ONdb1.table1TO'testuser'@'%'withgrantoption;当授予表权限时,MySQL将更新mysql。tables_priv表并授予列权限,MySQL将更新mysql.columns_priv表。同时这两个操作会触发MySQL更新内存中的哈希表column_priv_hash。与DB权限一样,表权限和列权限的修改会立即影响所有链接。说了这么多,好像grant命令是立即生效的,好像不需要执行flushprivileges?其实答案是这样的。grant命令授权后,就不需要专门执行flushprivileges了。flush权限的使用场景既然MySQL提供了flush权限,那肯定有适用的场景。那么,flush权限一般用在哪些场景呢?使用flush权限时,内存中的acl_users、acl_dbs等数组会被清空,然后从mysql.users、mysql.db等表中重新加载数据。也就是说,flushprivileges主要是用来让权限在数据库中保持一致。一般来说,内存中的数据和磁盘表中的数据是一致的,但是当我们直接使用DML语句修改权限表中的值时,内存中的数据和磁盘中的数据就会不一致。这时候就需要使用flushprivileges命令刷新内存,使内存和磁盘中的数据保持一致。小结使用grant命令后,不需要加flush权限,因为grant语句会同时修改数据表和内存。只有当我们直接使用DML语句对表中的权限字段进行不规则的修改时,才需要使用flush权限来刷新数据。