使用grant来给用户赋权,不过很多文档都提到过,grant之后要立即lflush privileges,是赋权语句生效。
那么现在就来看看grant语句和flush privileges语句分别做了什么事?
先创建一个用户
create user 'ua'@'%' identified by 'pa';全局权限
给ua赋一个最高权限
grant all privileges on *.* to 'ua'@'%' with grant option;这个命令做了两件事:
- 将mysql.user表中,用户ua这一行所有表示权限的字段的值都修改为Y。
- 内存里,从数组acl_users中找到这个用户对应的对象,将access值修改为二进制的全1。
这样新的连接使用ua登录的话,mysql就会从acl_users数组中找到这个用户的权限,并将权限值拷贝到这个线程对象中。
所以可以知道两点:
- grant对于全局权限,同时更新了磁盘和内存。
- 对于一个已经存在的连接,它的全局权限不受grant命令的影响。
至于收回权限的命令
revoke all privileges on *.* from 'ua'@'%';所作的操作正好与grant相反。
db权限
除了全局权限,mysql还可支持库级别的权限定义
grant all privileges on db1.* to 'ua'@'%' with grant option;这个grant命令做了如下两个操作
- 磁盘上,往mysql.db表中插入了一行记录,所有权限字段设置为Y。
- 内存里,增加一个对象到数组acl_dbs中,这个对象的权限位为全1。
每次判断一个用户对于一个数据库的读写权限的时候,都需要遍历一次acl_dbs数组,根据user, host, db找到匹配的对象,然后根据对象的权限位来判断。
也就是说,grant修改db权限的时候,是同时对磁盘和内存生效的。
修改db权限是会对已建立的连接也产生效果的。
表权限和列权限
表权限定义存放在表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;这两类权限的修改同样会影响已经建立的连接。
flush privileges使用场景
flush privileges命令会清空acl_users数组,然后从mysql.user表中读取数据重新加载到acl_users数组中。同样对db权限,表权限和列权限都做了这样的处理。
如何内存和磁盘数据表相同的话,不需要执行flush privileges,而使用grant/revoke来操作权限的话,内存和数据表就是保持同步更新的。
所以正常情况下grant命令后,不需要跟着执行flush privileges。
而需要使用flush privileges,当然是不正常的情况下,也就是操作不规范,直接使用DML语句操作系统权限表,造成了内存中的数据和数据表中的数据不一致,所以需要使用flush privileges来同步一下。