MySQL基础篇之视图与用户管理

一、视图(View)

1.1 什么是视图

视图是一种虚拟表 ,它本身不存储数据,只存储一条预定义的 SELECT 查询语句。当你查询视图时,MySQL 会动态执行这条 SELECT 语句,把结果当作一张表返回给你。

注意:这里的"视图"和事务 MVCC 中的"ReadView(读视图)"完全是两个概念,没有任何关系。

  • 本章的视图(View):数据库对象,是 SELECT 语句的别名/封装,是持久化的虚拟表。
  • 事务中的 ReadView:内存中的数据结构,用于 MVCC 判断数据版本可见性,事务结束就销毁。

1.2 创建视图

语法
复制代码
CREATE VIEW 视图名 AS SELECT语句;
示例
复制代码
CREATE VIEW myview AS
SELECT EMP.ename, DEPT.deptno, DEPT.dname
FROM EMP
INNER JOIN DEPT ON EMP.deptno = DEPT.deptno;

创建后,myview 就可以像普通表一样查询:

复制代码
SELECT * FROM myview;

这等价于直接执行那条复杂的多表连接查询。

1.3 视图的本质:不存数据,只存定义

视图的核心特点是只存储 SQL 定义,不存储查询结果数据

  • 视图的数据来自基表(底层的真实表),是查询时动态计算出来的;
  • 基表数据变化时,视图的查询结果也会随之变化;
  • 对视图执行 DML(INSERT/UPDATE/DELETE),本质上是在修改基表的数据------因为视图本身没有数据可改。

视图不存储数据,对视图的修改最终落到基表上;基表变了,查询视图的结果自然也变了。 但不是所有视图都能修改,见 1.5 节。

1.4 视图的优点与用途

优点 说明
简化复杂查询 把多表连接、子查询等复杂 SQL 封装成视图,使用时只需 SELECT * FROM 视图名
权限控制 只给用户开放视图的查询权限,不开放基表,从而隐藏敏感字段(比如工资、身份证号)
数据独立性 基表结构变化时,可以通过修改视图定义保持上层应用不变,实现逻辑数据独立性
逻辑清晰 给复杂查询起一个有意义的名字,提升 SQL 可读性和可维护性

1.5 可更新视图与不可更新视图

不是所有视图都能执行 INSERT/UPDATE/DELETE。

可更新视图必须同时满足
  1. 没有聚合函数(SUMCOUNTMAXMINAVG 等)
  2. 没有 DISTINCT
  3. 没有 GROUP BY / HAVING
  4. 没有 UNION / UNION ALL
  5. SELECT 列表和 WHERE 子句中没有子查询
  6. 基于单表(多表连接的视图一般不可更新)
  7. 没有引用其他不可更新的视图
示例
复制代码
-- 可更新视图(基于单表,无聚合)
CREATE VIEW v_emp10 AS
SELECT empno, ename, sal FROM EMP WHERE deptno = 10;

-- 可以修改(本质修改基表)
UPDATE v_emp10 SET sal = sal + 100 WHERE empno = 7782;

-- 不可更新视图(有聚合 + GROUP BY)
CREATE VIEW v_dept_avg AS
SELECT deptno, AVG(sal) AS avg_sal FROM EMP GROUP BY deptno;
-- 对 v_dept_avg 执行 UPDATE 会报错

1.6 视图的其他操作

复制代码
-- 查看所有视图(视图也是表,show tables 能看到)
SHOW TABLES;

-- 查看视图定义
SHOW CREATE VIEW 视图名;

-- 修改视图定义
CREATE OR REPLACE VIEW 视图名 AS 新的SELECT语句;
-- 或
ALTER VIEW 视图名 AS 新的SELECT语句;

-- 删除视图
DROP VIEW 视图名;

-- 同时删除多个视图
DROP VIEW 视图1, 视图2;

二、用户管理

2.1 用户数据存储在哪里

MySQL 是网络数据库服务,登录需要账号密码。用户信息本身也是数据,存储在 MySQL 自带的系统库 mysql 中。

复制代码
-- 切换到 mysql 系统库
USE mysql;

-- 查看所有表
SHOW TABLES;

其中最核心的是 user,存储所有用户的账号、密码、全局权限等信息。

复制代码
-- 查看表结构
DESC user;

-- 查看所有用户(垂直显示更清晰)
SELECT * FROM user \G;

2.2 MySQL 用户的唯一标识:'用户名'@'主机'

MySQL 的用户不是只由用户名唯一标识 ,而是由 '用户名'@'主机名' 共同唯一标识。

复制代码
'root'@'localhost'    和    'root'@'%'    是两个完全不同的用户!

它们可以有不同的密码、不同的权限。登录时,MySQL 根据你连接的来源 IP,在 user 表中找最精确匹配的那一条记录(host 越具体优先级越高),而不是模糊匹配。

Host 字段的常见形式
Host 值 含义
localhost 仅允许本地连接(Unix socket 或本地回环 TCP)
192.168.1.100 仅允许指定的单个 IP 连接
192.168.1.% 允许 192.168.1 网段的所有 IP 连接
%.example.com 允许指定域名后缀的主机连接
% 允许任意 IP 连接(最宽松)
关于内网/公网登录的正确理解

原文关于内网 IP 的解释有错误,这里修正:

  • 如果客户端和 MySQL 服务器在同一个内网 ,客户端连接时 MySQL 看到的来源 IP 就是客户端的内网 IP 本身 (不经过公网和 NAT)。此时可以把 host 精确设为内网 IP 或网段(如 '192.168.1.%'),不需要设为 %
  • 如果客户端跨公网连接 MySQL 服务器,请求经过路由器 NAT 后,MySQL 看到的来源 IP 是公网 IP 。此时需要把 host 设为对应的公网 IP,或者设为 %(任意 IP)。
  • % 的含义是"任意 IP 都能连接",和内网/公网无关。设为 % 意味着全网可达,生产环境慎用,应尽量精确限制来源 IP。

2.3 user 表核心字段解读

user 表有几十个字段,重点关注以下几类:

字段 含义
Host 允许登录的主机/IP(见 2.2)
User 账号名
authentication_string 密码的哈希摘要(不是明文密码)
plugin 认证插件。MySQL 8.0 默认 caching_sha2_password,5.7 默认 mysql_native_password
Select_privInsert_privUpdate_privDelete_priv 全局级别的增删改查权限,Y 表示拥有
Create_privDrop_privAlter_privGrant_priv 全局级别的 DDL 和授权权限
Super_priv 超级权限(kill 线程、修改全局变量等)
password_expired 密码是否已过期(Y/N
password_last_changed 密码最后修改时间
password_lifetime 密码有效期(天)
account_locked 账户是否被锁定(Y 表示锁定,无法登录)

其余字段大多是各类全局权限位(Y/N)、SSL 连接配置、资源限制(每小时最大查询数/连接数等)。

2.4 创建用户

语法
复制代码
CREATE USER '用户名'@'主机' IDENTIFIED BY '密码';
示例
复制代码
-- 创建一个只能本地登录的用户
CREATE USER 'zhangsan'@'localhost' IDENTIFIED BY '123456';

-- 创建一个允许任意 IP 登录的用户
CREATE USER 'lisi'@'%' IDENTIFIED BY '123456';

-- 创建一个允许指定网段登录的用户
CREATE USER 'wangwu'@'192.168.1.%' IDENTIFIED BY '123456';

注意:MySQL 8.0 中,CREATE USER 创建的用户默认没有任何权限 ,只能登录,连库都看不到。需要额外用 GRANT 授权。

2.5 删除用户

语法
复制代码
DROP USER '用户名'@'主机';
示例
复制代码
DROP USER 'zhangsan'@'localhost';

注意:必须写完整的 '用户名'@'主机',因为用户是由两者共同标识的。

2.6 修改密码

MySQL 8.0 推荐写法(标准)
复制代码
-- 修改指定用户密码
ALTER USER '用户名'@'主机' IDENTIFIED BY '新密码';

-- 修改当前登录用户自己的密码
ALTER USER CURRENT_USER() IDENTIFIED BY '新密码';
也可以用 SET PASSWORD
复制代码
SET PASSWORD FOR '用户名'@'主机' = '新密码';
已经废弃的写法
复制代码
-- ❌ MySQL 8.0 中已废弃/移除,会报错
SET PASSWORD FOR '用户名'@'主机' = PASSWORD('新密码');

PASSWORD() 函数在 MySQL 8.0 中已被移除,8.0 中直接写明文密码即可,MySQL 会自动用认证插件哈希后存储。

2.7 权限管理

2.7.1 权限的四个层级

MySQL 权限从粗到细分为四个层级:

层级 语法范围 作用范围
全局权限 *.* 所有库的所有表
数据库权限 库名.* 指定库的所有表
表权限 库名.表名 指定库的指定表
列权限 库名.表名(列1,列2) 指定表的指定列
2.7.2 常用权限列表
权限 作用
ALL PRIVILEGES / ALL 除 GRANT OPTION 和 PROXY 外的所有权限
SELECT 查询数据
INSERT 插入数据
UPDATE 更新数据
DELETE 删除数据
CREATE 创建数据库/表
DROP 删除数据库/表
ALTER 修改表结构
INDEX 创建/删除索引
CREATE VIEW 创建视图
SHOW VIEW 查看视图定义
CREATE ROUTINE 创建存储过程/函数
ALTER ROUTINE 修改/删除存储过程/函数
EXECUTE 执行存储过程/函数
CREATE USER 创建/删除/重命名用户
CREATE TABLESPACE 创建/删除/修改表空间
SHOW DATABASES 查看所有数据库
SUPER 超级权限(kill 线程、修改全局变量、关闭服务器等)
GRANT OPTION 将自己拥有的权限再授予其他用户
PROCESS 查看所有会话线程(SHOW PROCESSLIST)
RELOAD 执行 FLUSH 操作
SHUTDOWN 关闭 MySQL 服务器
FILE 服务器主机文件读写(LOAD DATA INFILE 等)
LOCK TABLES 显式锁表
CREATE TEMPORARY TABLES 创建临时表
REPLICATION SLAVE 从库复制权限
REPLICATION CLIENT 查询主从状态(SHOW MASTER/SLAVE STATUS)
EVENT 创建/删除/修改事件调度器
TRIGGER 创建/删除触发器
REFERENCES 创建外键约束
2.7.3 授权语法(GRANT)
复制代码
GRANT 权限列表 ON 库.对象 TO '用户名'@'主机';
示例
2.7.4 回收权限(REVOKE)
复制代码
REVOKE 权限列表 ON 库.对象 FROM '用户名'@'主机';
示例
复制代码
-- 回收指定库的删除权限
REVOKE DELETE ON company.* FROM 'zhangsan'@'localhost';

-- 回收所有权限(不含 GRANT OPTION)
REVOKE ALL PRIVILEGES ON *.* FROM 'lisi'@'%';

-- 回收 GRANT OPTION 权限
REVOKE GRANT OPTION ON *.* FROM 'wangwu'@'%';
2.7.5 查看用户权限
复制代码
-- 查看指定用户的权限
SHOW GRANTS FOR '用户名'@'主机';

-- 查看当前登录用户自己的权限
SHOW GRANTS FOR CURRENT_USER();

2.8 FLUSH PRIVILEGES 什么时候用

FLUSH PRIVILEGES 的作用是重新加载 mysql 库中的权限表到内存

操作方式 是否需要 FLUSH PRIVILEGES
CREATE USER / DROP USER / GRANT / REVOKE / ALTER USER 等标准语句管理用户 ❌ 不需要,MySQL 自动刷新权限缓存
直接用 INSERT / UPDATE / DELETE 手动修改 mysql.user 等权限表 ✅ 必须执行 FLUSH PRIVILEGES,否则修改不生效

生产环境推荐始终使用标准的用户管理语句(CREATE USER / GRANT 等),不要直接修改 mysql.user 表,避免权限不一致。

2.9 扩展:角色(Role)------ MySQL 8.0+

MySQL 8.0 引入了角色(Role)机制,可以把一组权限打包成一个角色,再把角色授予用户,简化权限管理。

复制代码
-- 创建角色
CREATE ROLE 'app_developer', 'app_reader';

-- 给角色授权
GRANT ALL PRIVILEGES ON app_db.* TO 'app_developer';
GRANT SELECT ON app_db.* TO 'app_reader';

-- 把角色授予用户
GRANT 'app_developer' TO 'zhangsan'@'localhost';

-- 用户启用角色(会话级)
SET ROLE 'app_developer';

-- 查看当前启用的角色
SELECT CURRENT_ROLE();
相关推荐
香菜TTT1 小时前
怎么实现MySQL的主从同步机制
数据库·mysql
Ahtacca1 小时前
Linux 基础实验:从终端操作到 C 语言编译
linux·运维·运维开发·虚拟机
邪修king1 小时前
Re:Linux 系统篇(二十九):动静态库Chapter2:动态库深度辨析 —— 核心本质、制作流程、双阶段查找模型与排错指南
android·java·linux·开发语言
云泽8083 小时前
从零搭建 WSL2 + Ubuntu C/C++ 开发环境:原理、实践与底层架构解析
linux·c++·windows·ubuntu·wsl2
2501_933670799 小时前
2026秋招数据分析岗备考路线:SQL、BI、项目与面试题拆解
数据库
bosins10 小时前
彻底解决 WSL 2.7+ 空闲自动关闭/内存回收导致 Docker 中断的问题
linux·docker·wsl·dashboard
LongRunning10 小时前
【Linux】H3网络(二)
linux
xx~t11 小时前
嵌入式学习——ARM1
linux·arm开发·嵌入式硬件·arm
xx~t11 小时前
嵌入式——ARM1(详细篇)
linux·arm开发·嵌入式硬件·arm