当前位置: 首页 > news >正文

Mysql 基础

文章目录

    • 执行顺序
      • 对照图
      • 完整逻辑顺序
      • 综合案例
    • DCL
      • 用户管理
      • 权限控制
    • 约束 Constraint
      • 根据案例理解约束
      • 外键
      • 外键语法
      • 外键约束
    • 子查询
      • 行子查询
      • 表子查询
    • 事物 Transaction
      • 四大特性 ACID
      • 并发事务问题
        • 脏读
        • 不可重复读
        • 幻读
        • 对比
    • 事务隔离级别
    • 参考

执行顺序

对照图

编写顺序和逻辑执行顺序的对照图

书写顺序 (写法)关键子句逻辑执行顺序作用说明
1SELECT6选出要返回的列或表达式,计算派生列、别名、聚合函数
2FROM1指定数据源表、视图、子查询;首先生成基表 / 视图的行集
3JOIN … ON1 (与 FROM 同阶段)多表连接;先做笛卡尔积,再按 ON 条件过滤
4WHERE2行过滤(非聚合条件);只保留满足条件的行
5GROUP BY3分组;把行集按键分桶,生成每组一条记录
6HAVING4组过滤(聚合后的条件)
7ORDER BY7排序;对最终结果集排序,默认升序 (ASC)
8LIMIT / OFFSET8取前 N 行或做分页;在排序后截取

完整逻辑顺序

  • FROM 含 JOIN … ON …
    • 先确定数据源,生成初步行集。
    • 多表连接时先做笛卡尔积,再用 ON 条件做行过滤。
    • 此阶段还会解析并执行子查询 / 派生表(即 (SELECT …) AS t)。
  • WHERE
    • 对每一行执行条件判断,结果为 TRUE 才能进入下一阶段
    • 只能使用原始列,不能使用后面 SELECT 中的别名,此时别名尚未生成
  • GROUP BY
    • WHERE 过滤后的行按照分组键“装桶”,每个桶对应一组
    • 若无 GROUP BY,则把所有行看作一组
  • HAVING
    • 针对分组后结果进一步过滤,常用于限制聚合结果
    • 可以使用聚合函数,也可以再次引用分组键
  • 计算聚合函数
  • SELECT
    • 生成最终列
    • 此时才产生列别名,因此别名可在 ORDER BY 使用,却不能在 WHERE 使用
  • ORDER BY
    • 对上一阶段结果集排序
    • 可用别名,列序号,或 SELECT 阶段产生别名
    • 不在 SELECT 中出现但是唯一识别的列也可以进行排序
  • LIMIT / OFFSET
    • 截取

综合案例

SELECTe.workno,e.name,e.age,e.entrydate,DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(e.entrydate, '%Y') AS years_worked
FROM emp AS e
WHERE e.gender = 'M'AND e.age BETWEEN 20 AND 35
GROUP BY e.workno, e.name, e.age, e.entrydate      -- 多列分组
HAVING COUNT(*) = 1                                -- 每个工号仅保留唯一记录
ORDER BY e.age ASC, e.entrydate DESC
LIMIT 5;
  • 写法 按图中顺序拼出来;
  • 实际执行 则先 FROMWHEREGROUP BYHAVINGSELECTORDER BYLIMIT
  • 由于 years_workedSELECT 阶段才计算,因此无法放在 WHERE,可以放 HAVINGORDER BY

DCL

用户管理

创建用户,'demo_user' 是用户名,'%' 是主机名,当前是设置了所有主机都能够被访问,'123456' 是密码

create user 'demo_user'@'%' identified by '123456';

可以通过查询 user 表查看创建用户结果

HostUserSelect_privInsert_privUpdate_privDelete_privCreate_privDrop_privReload_privShutdown_privProcess_privFile_privGrant_privReferences_privIndex_privAlter_privShow_db_privSuper_privCreate_tmp_table_privLock_tables_privExecute_privRepl_slave_privRepl_client_privCreate_view_privShow_view_privCreate_routine_privAlter_routine_privCreate_user_privEvent_privTrigger_privCreate_tablespace_privssl_typessl_cipherx509_issuerx509_subjectmax_questionsmax_updatesmax_connectionsmax_user_connectionspluginauthentication_stringpassword_expiredpassword_last_changedpassword_lifetimeaccount_lockedCreate_role_privDrop_role_privPassword_reuse_historyPassword_reuse_timePassword_require_currentUser_attributes
%demo_userNNNNNNNNNNNNNNNNNNNNNNNNNNNNN0000caching_sha2_password$A 005 005 005~W!;_u4_F,h6O}&xAtLnXWDO40tvxo.TjZ54ZDJ4Qe2jOg8M8XNswUaCz22N2025-06-05 21:18:23nullNNNnullnullnullnull

此时如果需要更换密码,则需要

alter user 'demo_user'@'%' identified with mysql_native_password by '123457';

mysql 8.0 之后就不再支持 mysql_native_paasowrd 而是改用 caching_sha2_password

如果需要删除用户,则需要

drop user 'demo_user'@'%';

权限控制

查询权限,正常用户的话,会输出以下信息,也就是不会给账户任何读写或者管理能力,只是声明了这个用户存在,但是对任何库,表以及视图没有操作权限

show grants for 'demo_user'@'%';

*.*数据库对象的通配写法,它由两个星号组成,分别表示授权范围的“库层”和“表层”

grant all privileges on mysql_demo.* to 'demo_user'@'%';

约束 Constraint

概念:数据库层面由 DDL 定义的规则,用于限制一张表(或多张表)中列的取值范围与关系从而确保数据的一致性、正确性与完整性。当插入、更新、删除的数据不符合约束条件时,MySQL 会拒绝执行并返回错误,防止“脏数据”落库。

约束 ≠ 单纯的业务校验。约束由服务器强制执行,不依赖应用代码,能跨所有客户端生效。

约束关键字作用典型意义
非空NOT NULL禁止列值为 NULL必填字段,如 username
唯一UNIQUE列(或列组)取值全局唯一登录邮箱、手机号
主键PRIMARY KEY唯一 + 非空;自动创建聚簇索引记录主身份标识
默认值DEFAULT expr未显式赋值时用默认表达式状态默认 ‘N’
检查CHECK (expr)行级布尔表达式必须为 TRUEage BETWEEN 0 AND 120
外键FOREIGN KEY … REFERENCES保证子表字段在父表存在,维护级联订单-用户关联
自增AUTO_INCREMENT数值列自动 +1(InnoDB 主键或唯一索引)简单流水号

根据案例理解约束

需求如下

字段名字段含义字段类型约束条件约束关键字
idID 唯一标识int主键,并且自动增长PRIMARY KEY, AUTO_INCREMENT
name姓名varchar(10)不为空,并且唯一NOT NULL, UNIQUE
age年龄int大于 0,并且小于等于 120CHECK
status状态char(1)如果没有指定该值,默认为 1DEFAULT
gender性别char(1)

根据需求创建数据表

create table user (id int primary key auto_increment comment '主键',name varchar(20) not null unique comment '姓名',age int check ( age > 0 and age <= 120 ) comment '年龄',status char(1) default '1' comment '状态',gender char(1) comment '性别',
) comment '用户表';

测试数据

/* 1. 成功:所有字段符合约束 */
INSERT INTO user (name, age, status, gender)
VALUES ('Alice', 25, '1', 'F');/* 2. 失败:name 为 NULL,触发 NOT NULL 约束 */
INSERT INTO user (name, age, status, gender)
VALUES (NULL, 30, '1', 'M');/* 3. 成功:省略 status,验证 DEFAULT 自动填充为 '1' */
INSERT INTO user (name, age, gender)
VALUES ('Bob', 40, 'M');/* 4. 失败:name 与上一条重复,触发 UNIQUE 约束 */
INSERT INTO user (name, age, gender)
VALUES ('Bob', 35, 'M');/* 5. 失败:age = 0,触发 CHECK 下界 */
INSERT INTO user (name, age, gender)
VALUES ('Charlie', 0, 'M');/* 6. 失败:age = 121,触发 CHECK 上界 */
INSERT INTO user (name, age, gender)
VALUES ('Diana', 121, 'F');/* 7. 成功:边界值 age = 1(通过 CHECK) */
INSERT INTO user (name, age, gender)
VALUES ('Eve', 1, 'F');/* 8. 成功:边界值 age = 120(通过 CHECK) */
INSERT INTO user (name, age, gender)
VALUES ('Frank', 120, 'M');

外键

概念:用来让两张表的数据之间建立链接,从而保证数据的一致性和完整性

完整概念:指在子表(child table)的某一列或多列上定义的规则,用来 引用父表(parent table)主键或唯一键的取值。当对这两张表进行插入、更新、删除时,MySQL 会自动检查并维护两张表之间的引用完整性(Referential Integrity),从而避免出现“孤儿数据”

外键语法

在创建数据表的时候新增外键

/* 父表:用户 */
CREATE TABLE user
(id   BIGINT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50) NOT NULL
) ENGINE = InnoDB COMMENT ='用户表';/* 子表:订单 */
CREATE TABLE orders
(id       BIGINT PRIMARY KEY AUTO_INCREMENT,order_no CHAR(20)       NOT NULL UNIQUE,user_id  BIGINT,amount   DECIMAL(10, 2) NOT NULL,status   ENUM ('NEW','PAID','CLOSED') DEFAULT 'NEW',/* 外键定义:引用 user(id),删除用户时级联删除订单 */CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB COMMENT ='订单表';

创建完数据表后新增外键

alter table orders add constraint fk_orders_user foreign key (user_id) references user (id);

删除外键

alter table orders drop foreign key fk_orders_user;

外键约束

动作MySQL 行为细节典型使用场景需要注意
NO ACTION检查时机:立即(与 RESTRICT 相同);若子表存在引用则直接报错,父表行不会被删/改。InnoDB 内部实现与 RESTRICT 一致,仅是语法保留。安全默认,禁止误删/误改父表。适合订单-客户这类“父子”强依赖场景,要先手动清理子表才能改父表。MySQL 8.0 以后仍无区别,只写其中一种即可。
RESTRICT行为同上,只是名字不同;标准 SQL 把 NO ACTION 用于“延迟检查”,但 InnoDB 没有延迟功能,两者等价。同上。——
CASCADE删除 / 更新父表行时,自动同步子表对应行:- ON DELETE CASCADE ⇒ 删除子表行。- ON UPDATE CASCADE ⇒ 把外键列改成最新值。父表记录生命周期与子表一致,比如:用户删除后连同购物车、头像记录一并删除。慎用:大量级联删除可能锁表或误删;建议加索引并在业务上确保符合预期。
SET NULL删除 / 更新父表行时,把子表外键列设为 NULL。列必须允许 NULL。保留子表历史而解除关联,如删除员工后把 orders.employee_id 置空。更新为 NULL 仅影响外键列,不会递归到更下级。
SET DEFAULT删除 / 更新父表行时,将子表外键列改为 列默认值实际很少用,因 InnoDB 不支持;只有 NDB、Tokudb 等少数引擎可用。在 InnoDB 里若尝试创建会报 ERROR 1215 (HY000)

在 MySQL InnoDB 中,如果 foreign key 什么都不写的的话,系统默认采用 NO ACTION / RESTRICT,也就是“先检查,如果子表仍然有引用就就直接报错并阻止父表行被删除或更新”

按照上文测试数据进行测试,此时 foreign key 没有设置,那么就是 RESTRICT,此时执行以下指令

delete from user where id = 1;

会爆出以下错误

[23000][1451] Cannot delete or update a parent row: a foreign key constraint fails (`mysql_demo`.`orders`, CONSTRAINT `fk_orders_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`))

将外键约束设置为 on delete cascade on update cascade,此时再执行删除指令,删除父表行,子表对应行自动删除

将外键约束设置为 on delete set null on update set null,此时再执行删除指令,删除父表行,子表对应行设置为 NULL

子查询

行子查询

-- 查询与 “张无忌” 的薪资及直属领导相同的员工信息select * from emp where (salary, managerid) = (select salary, managerid from emp where name = "张无忌") and name != '张无忌'

表子查询

-- 查询与 “鹿杖客”,“宋远桥” 的职位和薪资相同的员工信息select * from emp where (salary, job) in (select salary, job from emp where name = "鹿杖客" or name = "宋远桥") and name != '宋远桥' and name != '鹿杖客'

事物 Transaction

概念:一组要么 全部成功、要么 全部失败回滚 的操作单元。它把多条 INSERT / UPDATE / DELETE 等语句打包成一个整体,确保数据始终处于一致状态。

MySQL 事务由存储引擎实现。InnoDB 完整支持事务;

MySQL 事务是默认自动提交的,也就是,当执行一条 DML 语句,MySQL 会立即隐式提交事务。

查询事务状态

select @@autocommit;

设置事务提交方式,1为自动提交,0为手动提交,该设置只对当前会话有效

set @@autocommit = 1;

当设置为0时,在当前对话中,每次执行 DML 语句都要加上 commit 语句提交事务,如果发现语句错误还能执行 rollback 语句回滚事务

select * from account where name = '张三';  
update account set money = money - 1000 where name = '张三';  
update account set money = money + 1000 where name = '李四';
commit;

也可以单独对每一段 SQL 设置手动开启事务

start transaction | begin transaction

根据上述案例就可以改成

start transaction
select * from account where name = '张三';  
update account set money = money - 1000 where name = '张三';  
update account set money = money + 1000 where name = '李四';
commit;

四大特性 ACID

  • 原子性 Atomicity:事务是不可分割的最小操作但愿,要么全部成功,要么全部失败
  • 一致性 Consistency:事务完成时,必须使所有数据都保持一致状态
  • 隔离性 Isolation:数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行
  • 持久性 Durability:事务一旦提交或回滚,它对数据库中的数据的改变就是永久的
特性含义在 InnoDB 中的实现要点
A 原子性 (Atomicity)事务中的所有操作要么全部提交,要么全部回滚undo 日志(回滚日志)
C 一致性 (Consistency)事务开始前后,数据必须满足所有约束和规则崩溃恢复、外键/约束检查
I 隔离性 (Isolation)并发事务之间互不干扰,隔离级别可调MVCC + 锁机制
D 持久性 (Durability)一旦提交即永久保存redo 日志 + 双写缓冲

并发事务问题

脏读

一个事务 A 读到了另一个事务 B 尚未提交的数据。如果随后事务 B 发生了回滚,事务 A 就等于使用了从未真正存在的脏数据,导致业务逻辑和结果都不可信。

脏读 = 读到别人未提交的数据,是隔离级别最低时的典型并发问题

在实际生产中,保持 READ COMMITTED 或者默认 REPEATABLE READ 足以消除脏风险

第一个事务

mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.000 sec)mysql> select * from account;
+------+-------+
| name | money |
+------+-------+
| xiao |  2000 |
| ming |  2000 |
+------+-------+
2 rows in set (0.001 sec)

第二个事务

mysql> start transaction;
Query OK, 0 rows affected (0.000 sec)mysql> update account set money = money + 1000 where name = "xiao";
Query OK, 1 row affected (0.002 sec)
Rows matched: 1  Changed: 1  Warnings: 0

第一个事务

mysql> select * from account;
+------+-------+
| name | money |
+------+-------+
| xiao |  3000 |
| ming |  2000 |
+------+-------+
2 rows in set (0.000 sec)

需要将事务隔离级别设置高于 read uncommitted 就能解决脏读问题

不可重复读

同一个事务在两次读取同一行记录时,前后读到的数据内容不一致,在第一次读取和第二次读取之间,另一事务已经提交了对该行的 UPDATE 或者 DELETE 操作

让当前事务“重复”读取时得到不同结果,破坏了业务对一致性的假设

第一个事务

mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.001 sec)mysql> start transaction;
Query OK, 0 rows affected (0.000 sec)mysql> select * from account;
+------+-------+
| name | money |
+------+-------+
| xiao |  2000 |
| ming |  2000 |
+------+-------+
2 rows in set (0.001 sec)

第二个事务

mysql> start transaction;
Query OK, 0 rows affected (0.000 sec)mysql> update account set money = money + 1000 where name = "xiao";
Query OK, 1 row affected (0.001 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> commit;
Query OK, 0 rows affected (0.002 sec)

第一个事务

mysql> select * from account;
+------+-------+
| name | money |
+------+-------+
| xiao |  2000 |
| ming |  2000 |
+------+-------+
2 rows in set (0.001 sec)mysql> select * from account;
+------+-------+
| name | money |
+------+-------+
| xiao |  3000 |
| ming |  2000 |
+------+-------+

需要将事务隔离级别设置高于 read committed 就能解决脏读问题

幻读

同一个事务在两次执行相同的范围查询时,第二次看到了“凭空多出来的新数据”

在两次查询时,另一个事务已经提交了插入或删除,而这些新旧行符合原来的查询条件,于是第一次“没看见”的记录在第二次突然出现/笑死,像个幽灵一样

第一个对话

mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.000 sec)mysql> select * from account where name = "hong";
Empty set (0.000 sec)

第二个对话

mysql> start transaction;
Query OK, 0 rows affected (0.000 sec)mysql> insert into account (name, money) values ('hong', 1000);
Query OK, 1 row affected (0.000 sec)mysql> commit;
Query OK, 0 rows affected (0.002 sec)

第一个对话

mysql> select * from account where name = "hong";
Empty set (0.001 sec)mysql> insert into account (name, money) values ("hong", 2000);
Query OK, 1 row affected (0.003 sec)

第二个对话

mysql> select * from account;
+------+-------+
| name | money |
+------+-------+
| xiao |  3000 |
| ming |  2000 |
| hong |  1000 |
+------+-------+
3 rows in set (0.000 sec)

设置级别为 repeatable read,虽然能解决不可重复读的并发异常,但是会导致幻读的并发异常,解决幻读的并发异常需要将隔离级别设置为 serialization。(如果将 name 设置 unique 唯一,幻读的并发异常更加明显)

对比
并发异常变化点典型触发
脏读读到 未提交 的行或行内容另一事务尚未提交
不可重复读同一行内容前后不一致另一事务 已提交 修改该行
幻读行集合 前后不一致(多/少行)另一事务 已提交 插入或删除

事务隔离级别

隔离级别 Isolation Level 决定了并发事务之间可以“看见”彼此未提交或者已提交变更的程度。这是 ACID 中隔离性 Isolation 的具体实现参数,> 直接影响脏读、不可重复读、幻读等并发异常是否会发生,以及系统的并发吞吐量。

级别(由低到高)MySQL 语法能否脏读能否不可重复读能否幻读并发性能
READ UNCOMMITTEDSET SESSION transaction_isolation=‘READ-UNCOMMITTED’;可能可能可能最高
READ COMMITTED‘READ-COMMITTED’可能可能较高
REPEATABLE READ (MySQL 默认)‘REPEATABLE-READ’标准视角:可能InnoDB:通过间隙锁/Next-Key 锁可避免
SERIALIZABLE‘SERIALIZABLE’最低
  • 级别越高,异常越少,但锁持有时间越长、并发能力越低
  • MySQL 8/InnoDB 默认 REPEATABLE READ,配合 MVCC + 间隙锁,已能消除绝大多数线上幻读场景

查看隔离级别

select @@transaction_isolation;

设置事务隔离级别,session 是当前会话隔离级别,global 是全局隔离级别

set session|global transaction isolation level read committed;

参考

  • MySQL学习笔记 | 智云知识

相关文章:

  • 第二十七章 位置参数
  • Pinocchio 库详解及其在足式机器人上的应用
  • FPGA静态功耗
  • 【FPGA开发】DDS信号发生器设计
  • 【动态规划】子序列问题(二)
  • Python安装使用教程
  • 国家奖学金答辩PPT+文稿
  • 第三章 内存
  • AUTOSAR实战教程--DoIP_01_配置项解释
  • 在VSCode中使用Ultralytics扩展
  • vscode 配置 latex
  • 港理工:LLM推理与推荐能力集成
  • 机器学习 [白板推导](四)[降维]
  • 计数排序_桶排序
  • hot100 -- 10.回溯系列
  • 电流舵DAC设计(二)
  • Vue-Leaflet地图组件开发(三)地图控件与高级样式设计
  • Python学习——排序
  • Java严格模式withResolverStyle解析日期错误及解决方案
  • AI架构师修炼之道
  • html网站开发心得体会/市场营销手段13种手段
  • 问佛教网站大师做早课烧香烛可以吗/公司产品推广文案
  • 南昌疫情最新政策/兰州seo优化
  • wordpress整站无刷新/搜索引擎排名优化包括哪些方面
  • 动态网站建设实训收获/国内新闻最新5条
  • 宿迁房产交易中心官网/免费seo工具大全