一、视图(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。
可更新视图必须同时满足
示例
— 可更新视图(基于单表,无聚合)
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 字段的常见形式
| 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_priv、Insert_priv、Update_priv、Delete_priv | 全局级别的增删改查权限,Y 表示拥有 |
| Create_priv、Drop_priv、Alter_priv、Grant_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 库中的权限表到内存。
| 用 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();
网硕互联帮助中心


评论前必须登录!
注册