Day906.grant语句 -MySQL实战

news2025/1/6 19:29:38

grant语句

Hi,我是阿昌,今天学习记录的是关于grant语句的内容。

在 MySQL 里面,grant 语句是用来给用户赋权的。

不知道有没有见过一些操作文档里面提到,grant 之后要马上跟着执行一个 flush privileges 命令,才能使赋权语句生效。

那么,grant 之后真的需要执行 flush privileges 吗?如果没有执行这个 flush 命令的话,赋权语句真的不能生效吗?


为了便于说明,先创建一个用户:

create user 'ua'@'%' identified by 'pa';

这条语句的逻辑是创建一个用户’ua’@’%’,密码是 pa。

注意,在 MySQL 里面,用户名 (user)+ 地址 (host) 才表示一个用户,因此 ua@ip1 和 ua@ip2 代表的是两个不同的用户。


这条命令做了两个动作:

  1. 磁盘上,往 mysql.user 表里插入一行,由于没有指定权限,所以这行数据上所有表示权限的字段的值都是 N;
  2. 内存里,往数组 acl_users 里插入一个 acl_user 对象,这个对象的 access 字段值为 0。

图 1 就是这个时刻用户 ua 在 user 表中的状态。

图 1 mysql.user 数据行

在 MySQL 中,用户权限是有不同的范围的。

接下来,按照用户权限范围从大到小的顺序依次和你说明。


一、全局权限

全局权限,作用于整个 MySQL 实例,这些权限信息保存在 mysql 库的 user 表里。

如果要给用户 ua 赋一个最高权限的话,语句是这么写的:

grant all privileges on *.* to 'ua'@'%' with grant option;

这个 grant 命令做了两个动作:

  1. 磁盘上,将 mysql.user 表里,用户’ua’@’%'这一行的所有表示权限的字段的值都修改为‘Y’;
  2. 内存里,从数组 acl_users 中找到这个用户对应的对象,将 access 值(权限位)修改为二进制的“全 1”。

在这个 grant 命令执行完成后,如果有新的客户端使用用户名 ua 登录成功,MySQL 会为新连接维护一个线程对象,然后从 acl_users 数组里查到这个用户的权限,并将权限值拷贝到这个线程对象中。

之后在这个连接中执行的语句,所有关于全局权限的判断,都直接使用线程对象内部保存的权限位。

基于上面的分析可以知道:

  1. grant 命令对于全局权限,同时更新了磁盘和内存。命令完成后即时生效,接下来新创建的连接会使用新的权限。
  2. 对于一个已经存在的连接,它的全局权限不受 grant 命令的影响。

需要说明的是,一般在生产环境上要合理控制用户权限的范围。上面用到的这个 grant 语句就是一个典型的错误示范。

如果一个用户有所有权限,一般就不应该设置为所有 IP 地址都可以访问。

如果要回收上面的 grant 语句赋予的权限,可以使用下面这条命令:

revoke all privileges on *.* from 'ua'@'%';

这条 revoke 命令的用法与 grant 类似,做了如下两个动作:

  1. 磁盘上,将 mysql.user 表里,用户’ua’@’%'这一行的所有表示权限的字段的值都修改为“N”;
  2. 内存里,从数组 acl_users 中找到这个用户对应的对象,将 access 的值修改为 0。

二、db 权限

除了全局权限,MySQL 也支持库级别的权限定义。

如果要让用户 ua 拥有库 db1 的所有权限,可以执行下面这条命令:

grant all privileges on db1.* to 'ua'@'%' with grant option;

基于库的权限记录保存在 mysql.db 表中,在内存里则保存在数组 acl_dbs 中。

这条 grant 命令做了如下两个动作:

  1. 磁盘上,往 mysql.db 表中插入了一行记录,所有权限位字段设置为“Y”;
  2. 内存里,增加一个对象到数组 acl_dbs 中,这个对象的权限位为“全 1”。

图 2 就是这个时刻用户 ua 在 db 表中的状态。

图 2 mysql.db 数据行

每次需要判断一个用户对一个数据库读写权限的时候,都需要遍历一次 acl_dbs 数组,根据 user、host 和 db 找到匹配的对象,然后根据对象的权限位来判断。也就是说,grant 修改 db 权限的时候,是同时对磁盘和内存生效的

grant 操作对于已经存在的连接的影响,在全局权限和基于 db 的权限效果是不同的。


接下来,做一个对照试验来分别看一下。

图 3 权限操作效果

需要说明的是,图中 set global sync_binlog 这个操作是需要 super 权限的。

可以看到,虽然用户 ua 的 super 权限在 T3 时刻已经通过 revoke 语句回收了,但是在 T4 时刻执行 set global 的时候,权限验证还是通过了。

这是因为 super 是全局权限,这个权限信息在线程对象中,而 revoke 操作影响不到这个线程对象。而在 T5 时刻去掉 ua 对 db1 库的所有权限后,在 T6 时刻 session B 再操作 db1 库的表,就会报错“权限不足”。

这是因为 acl_dbs 是一个全局数组,所有线程判断 db 权限都用这个数组,这样 revoke 操作马上就会影响到 session B。

这里在代码实现上有一个特别的逻辑,如果当前会话已经处于某一个 db 里面,之前 use 这个库的时候拿到的库权限会保存在会话变量中。

可以看到在 T6 时刻,session C 和 session B 对表 t 的操作逻辑是一样的。但是 session B 报错,而 session C 可以执行成功。

这是因为 session C 在 T2 时刻执行的 use db1,拿到了这个库的权限,在切换出 db1 库之前,session C 对这个库就一直有权限。


三、表权限和列权限

除了 db 级别的权限外,MySQL 支持更细粒度的表权限和列权限

其中,表权限定义存放在表 mysql.tables_priv 中,列权限定义存放在表 mysql.columns_priv 中。

这两类权限,组合起来存放在内存的 hash 结构 column_priv_hash 中。

这两类权限的赋权命令如下:

create table db1.t1(id int, a int);

grant all privileges on db1.t1 to 'ua'@'%' with grant option;
GRANT SELECT(id), INSERT (id,a) ON mydb.mytbl TO 'ua'@'%' with grant option;

跟 db 权限类似,这两个权限每次 grant 的时候都会修改数据表,也会同步修改内存中的 hash 结构。

因此,对这两类权限的操作,也会马上影响到已经存在的连接。

看来 grant 语句都是即时生效的,那这么看应该就不需要执行 flush privileges 语句了呀。答案也确实是这样的。

flush privileges 命令会清空 acl_users 数组,然后从 mysql.user 表中读取数据重新加载,重新构造一个 acl_users 数组。

也就是说,以数据表中的数据为准,会将全局权限内存数组重新加载一遍

同样地,对于 db 权限、表权限和列权限,MySQL 也做了这样的处理。

也就是说,如果内存的权限数据和磁盘数据表相同的话,不需要执行 flush privileges。

如果都是用 grant/revoke 语句来执行的话,内存和数据表本来就是保持同步更新的。

因此,正常情况下,grant 命令之后,没有必要跟着执行 flush privileges 命令。


四、flush privileges 使用场景

那么,flush privileges 是在什么时候使用呢?

显然,当数据表中的权限数据跟内存中的权限数据不一致的时候,flush privileges 语句可以用来重建内存数据,达到一致状态。

这种不一致往往是由不规范的操作导致的,比如直接用 DML 语句操作系统权限表。

来看一下下面这个场景:
图 4 使用 flush privileges

可以看到,T3 时刻虽然已经用 delete 语句删除了用户 ua,但是在 T4 时刻,仍然可以用 ua 连接成功。

原因就是,这时候内存中 acl_users 数组中还有这个用户,因此系统判断时认为用户还正常存在。在 T5 时刻执行过 flush 命令后,内存更新,T6 时刻再要用 ua 来登录的话,就会报错“无法访问”了。

直接操作系统表是不规范的操作,这个不一致状态也会导致一些更“诡异”的现象发生。

比如,前面这个通过 delete 语句删除用户的例子,就会出现下面的情况:

图 5 不规范权限操作导致的异常
可以看到,由于在 T3 时刻直接删除了数据表的记录,而内存的数据还存在。

这就导致了:

  1. T4 时刻给用户 ua 赋权限失败,因为 mysql.user 表中找不到这行记录;
  2. 而 T5 时刻要重新创建这个用户也不行,因为在做内存判断的时候,会认为这个用户还存在。

五、总结

介绍MySQL 用户权限在数据表和内存中的存在形式,以及 grant 和 revoke 命令的执行逻辑。

grant 语句会同时修改数据表和内存,判断权限的时候使用的是内存数据。因此,规范地使用 grant 和 revoke 语句,是不需要随后加上 flush privileges 语句的。

flush privileges 语句本身会用数据表的数据重建一份内存权限数据,所以在权限数据可能存在不一致的情况下再使用。而这种不一致往往是由于直接用 DML 语句操作系统权限表导致的,所以尽量不要使用这类语句。

另外,在使用 grant 语句赋权时,可能还会看到这样的写法:

grant super on *.* to 'ua'@'%' identified by 'pa';

这条命令加了 identified by ‘密码’, 语句的逻辑里面除了赋权外,还包含了:

  1. 如果用户’ua’@’%'不存在,就创建这个用户,密码是 pa;
  2. 如果用户 ua 已经存在,就将密码修改成 pa。

这也是一种不建议的写法,因为这种写法很容易就会不慎把密码给改了。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/386096.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搞懂它,带你学会高效配置交换机!

想了解更多IT学习资料,可关注公众号“IT运维大本营” 不同网段的用户想要进行三层通信,必须借助于路由表项,而VLANIF接口只能生成直连路由,实现不同网段间通过同一台设备互通,对于不同网段间跨设备…

【Linux】虚拟机设置ISO镜像、配置CentOS 7、设置快照

目录 一、设置ISO镜像 1.设置或编辑 2.配置光驱(DVD) 3.虚拟机快捷键设置 4.启动虚拟机 二、配置CentOS 7 三、设置快照 四、​​​​​​​虚拟网卡不显示怎么办? 💟 创作不易,不妨点赞💚评论❤️收…

安装打印机驱动程序的操作步骤,详细方法介绍

安装打印机驱动程序是使用打印机的前提条件,因此学会正确的安装方法是非常重要的。下面是安装打印机驱动程序的详细步骤分析,为你全面的讲解安装和出现故障如何处理等问题。 一.安装打印机的准备工作 在安装打印机驱动程序之前,需要先准备好…

【Java集合框架】篇六:Collections工具类

Collections 是一个操作 Set、List 和 Map 等集合的工具类。 1。 常用方法 Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法(均为static方法)&…

软件测试6

一 css书写位置,引入方式 1.内嵌式:css写在style标签中,放在title标签的后面,因为html代码和css代码混在同一个文件中,所以叫内嵌式。 2.外链式:css代码和html代码分离,使用link标签设置href属…

UE 蓝图上帝视角

UE 蓝图上帝视角 UE5蓝图实现相机上帝视角控制,包括绕点旋转,水平平移,远近缩放 实现效果 绕点旋转 水平平移 实现功能 左键鼠标平移(相对于场景水平面平移)右键绕点旋转中间键视角前后移动(可以理解成…

linux网络管理、测试网络连通性

一、网络管理 在rhel7上,同时支持network.service和NetworkMananger.service(简称NM)。在rhel8上,已经废弃network.service,因此只能通过NM进行网络配置,包括静态ip和动态ip。在rhel8上,必须开启…

安卓短信自动填充踩坑

安卓短信自动填充踩坑 前言 最近弄了个短信自动填充功能,一开始觉得很简单,不就是动态注册个广播接收器去监听短信消息不就可以了吗?结果没这么简单,问题就出在机型的适配上。小米的短信权限、荣耀的短信监听都是坑,…

LabVIEW绘制带有两个不同标尺的波形图/图表

LabVIEW绘制带有两个不同标尺的波形图/图表拥有多组不同标尺的数据,想要在LabVIEW中显示这些数据。能否在同一张波形图/图表中使用多个不同的标尺绘制这些数据?通过在同一波形图上使用多个轴,可以使用不同的标尺绘制数据。请按照以下步骤操作…

【网络】-- 网络基础

(本文是网络的宏观的概念铺垫) 目录 计算机网络背景 网络发展 认识 "协议" 网络协议初识 协议分层 OSI七层模型 TCP/IP 五层(或四层)模型 报头 以太网 碰撞 路由器 IP地址和MAC地址 IP地址与MAC地址总结 IP地址 MAC地址 计算机…

混合图像python旗舰版

仔细看这个图像。然后后退几米再看。你看到了什么?混合图像是指将一张图片的低频与另一张图片的高频相结合的图片。根据观看距离的不同,所得到的图像有两种解释。在上面的图片中,你可以看到阿尔伯特爱因斯坦,一旦你离开屏幕或缩小…

UG曲面造型-搭建轮廓和曲面创建(通过网格曲面,填充曲面,割面补面,曲面合格性分析)

先在xy平面创建一段圆弧,圆弧两端固定在坐标轴上在yz平面创建一段圆弧,圆弧两端固定在坐标轴上最后在xz平面创建圆弧,圆弧两端与之前的两个圆弧端点重合完成之后的草图如下:接下来构造曲面:方法1:采用通过曲…

HTML、CSS学习笔记5(移动端基础知识、Flex布局)

一、移动端基础知识 1.PC端和移动端区别 移动端:手机版网页,手机屏幕小,网页宽度多数为100%,没有版心 PC端:电脑版网页,屏幕大,网页固定版心 PC端和移动端不是同一个网页 2.如何在电脑里面…

pytorch-模型训练常用的torchvision包。关于数据、模型、数据增强、优化器、损失函数。用官方的实现,自定义模型训练

pytoch关于图像数据的部分 一般情况下处理图像、文本、音频和视频数据时,可以使用标准的Python包来加载数据到一个numpy数组中。 然后把这个数组转换成 torch.*Tensor。 图像可以使用 Pillow, OpenCV 音频可以使用 scipy, librosa 文本可以使用原始Python和Cython…

3D立体视觉成像原理介绍【一 】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言什么是基线?基线是如何影响3D图像质量激光三角测量飞行时间结构光相机时间编码结构光前言 本文将介绍3D立体视觉的成像原理,包括【激光三…

【JUC2022】第五章 ThreadLocal

【JUC2022】第五章 ThreadLocal 文章目录【JUC2022】第五章 ThreadLocal一、是什么二、案例三、使用规范四、源码分析五、内存泄漏问题六、实际应用 Demo一、是什么 ThreadLocal 提供线程局部变量,这些变量与正常的变量不同,因为每一个线程在访问 Threa…

Qt Widget之QMainWindow

目录 一 QMainWindow整体概况 二 菜单栏 三 工具栏 四 状态栏 五 铆接部件 六 核心部件 七 总体效果 一 QMainWindow整体概况 QMainWindow是主窗口程序,由以下几个部分构成:菜单栏,状态栏,工具栏,铆接部件和核…

Nginx优化服务和防盗链

Nginx优化服务和防盗链一、长连接1、修改主配置文件2、测试3、在主配置文件添加4、验证二、Nginx第三方模块1、开源的echo模块2、查看是否成功3、加echo模块步骤4、网页测试验证三、搭建虚拟主机1、编译安装好nginx后,对主配置文件进行修改2、创建文件3、验证四、防…

Android 源码中的 JNI,到底是如何使用的?

Linux下 JNI的使用学习 Android 其中涉及对 JNI 的使用;JNI的使用对于 Android 来说又是十分的重要和关键。那么到底 Java 到底是如何调用 C/C 的,下面是非常简单的计算器源码,只是用来熟悉JNI的基本语法,其中我自己碰到过的一个问…

Unity 使用L2Localization实现App切换多国语言

Unity 使用 L2 Localization实现App切换多国语言一、L2 Localization介绍二、使用步骤1.导入插件,新建Language和Term2.开始使用,切换语言总结提示:以下是本篇文章正文内容,会提供自己的插件下载地址 一、L2 Localization介绍 这…