MySQL数据定义与数据操作综合实战示例
作者:troy128
这篇是 MySQL 入门系列的第二篇,正好接着你之前看的底层存储机制,把最常用的 DDL(数据定义)和 DML(数据操作)语法捋一遍。核心就一句话:DDL 管表结构,DML 管表数据,两者别混用。
1. 引言
在上一篇文章中,我们介绍了 MySQL 的基本概念、安装配置以及常用客户端工具的使用。本篇将深入 MySQL 的核心操作——数据定义语言(DDL)与数据操作语言(DML),带你掌握建库、建表、增删改查等最常用的技能。
无论你是刚接触数据库的新手,还是希望系统梳理基础知识的开发者,本文都会用清晰的示例和通俗的解释,帮你快速上手 MySQL 的数据定义与数据操作。
2. 数据定义语言(DDL)基础
数据定义语言(Data Definition Language,DDL)用于定义和管理数据库对象,主要包括数据库、表、索引、视图等。DDL 的核心操作可以概括为「增删改查」四个字:创建(CREATE)、删除(DROP)、修改(ALTER)和查看(SHOW / DESCRIBE)。
2.1 数据库的创建与删除
创建数据库使用 CREATE DATABASE 语句,可以同时指定字符集和排序规则:
-- 创建数据库,指定 utf8mb4 字符集 CREATE DATABASE IF NOT EXISTS mydb DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;
删除数据库使用 DROP DATABASE,操作前请务必确认,因为该操作不可恢复:
DROP DATABASE IF EXISTS mydb;
查看当前实例下有哪些数据库:
SHOW DATABASES;
2.2 表的创建
表是数据库中存储数据的基本单位。创建表时需要定义字段名、数据类型以及约束条件:
CREATE TABLE IF NOT EXISTS student ( id INT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', name VARCHAR(50) NOT NULL COMMENT '姓名', age TINYINT UNSIGNED DEFAULT 0 COMMENT '年龄', email VARCHAR(100) UNIQUE COMMENT '邮箱', created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生表';
常用数据类型速查:
| 数据类型 | 说明 | 典型用途 |
|---|---|---|
| INT / BIGINT | 整数 | 主键、计数 |
| VARCHAR(n) | 变长字符串 | 姓名、地址 |
| CHAR(n) | 定长字符串 | 固定长度编码 |
| DECIMAL(p,s) | 精确小数 | 金额 |
| DATE / DATETIME | 日期 / 日期时间 | 生日、创建时间 |
| TEXT | 长文本 | 文章内容 |
| BOOLEAN / TINYINT(1) | 布尔 | 状态标记 |
2.3 修改表结构
使用 ALTER TABLE 可以动态调整表结构,常见操作如下:
-- 新增字段 ALTER TABLE student ADD COLUMN phone VARCHAR(20) COMMENT '电话'; -- 修改字段类型 ALTER TABLE student MODIFY COLUMN age SMALLINT UNSIGNED DEFAULT 0 COMMENT '年龄'; -- 重命名字段 ALTER TABLE student CHANGE COLUMN email contact_email VARCHAR(100) COMMENT '联系邮箱'; -- 删除字段 ALTER TABLE student DROP COLUMN phone;
2.4 删除表
DROP TABLE IF EXISTS student;
注意:
DROP TABLE会连同表结构和数据一起删除,执行前务必做好备份。
3. 数据操作语言(DML)核心
数据操作语言(Data Manipulation Language,DML)用于对表中的数据进行增、删、改、查,是日常开发中使用最频繁的 SQL 语句。
3.1 插入数据(INSERT)
单行插入:
INSERT INTO student (name, age, email)
VALUES ('张三', 20, 'zhangsan@example.com');
多行批量插入:
INSERT INTO student (name, age, email) VALUES
('李四', 22, 'lisi@example.com'),
('王五', 21, 'wangwu@example.com'),
('赵六', 23, 'zhaoliu@example.com');
插入时也可以省略字段列表,但必须按表定义的字段顺序提供全部值(不推荐,易出错):
INSERT INTO student VALUES (NULL, '孙七', 24, 'sunqi@example.com', NOW());
3.2 查询数据(SELECT)
查询是 DML 中使用频率最高的操作。基础查询语法:
-- 查询所有字段 SELECT * FROM student; -- 查询指定字段 SELECT id, name, age FROM student; -- 带条件查询 SELECT id, name, age FROM student WHERE age > 20; -- 排序 SELECT id, name, age FROM student ORDER BY age DESC; -- 分页 SELECT id, name, age FROM student ORDER BY id LIMIT 10 OFFSET 0;
常用条件与运算符:
| 运算符 | 说明 | 示例 |
|---|---|---|
| = / != | 等于 / 不等于 | WHERE age = 20 |
| > / < / >= / <= | 比较 | WHERE age >= 20 |
| BETWEEN … AND … | 区间 | WHERE age BETWEEN 20 AND 25 |
| IN (…) | 在集合中 | WHERE name IN ('张三','李四') |
| LIKE | 模糊匹配 | WHERE name LIKE '张%' |
| AND / OR | 逻辑与 / 或 | WHERE age > 20 AND name LIKE '张%' |
| IS NULL / IS NOT NULL | 空值判断 | WHERE email IS NULL |
3.3 更新数据(UPDATE)
更新数据时务必带上 WHERE 条件,否则会更新全表数据:
-- 更新单条记录 UPDATE student SET age = 21 WHERE id = 1; -- 更新多条记录 UPDATE student SET age = age + 1 WHERE age < 20; -- 更新多个字段 UPDATE student SET age = 22, email = 'new@example.com' WHERE id = 2;
安全提示:生产环境中执行
UPDATE前,建议先用相同条件的SELECT确认影响范围。
3.4 删除数据(DELETE)
删除数据同样需要谨慎使用 WHERE:
-- 删除指定记录 DELETE FROM student WHERE id = 3; -- 清空表数据(保留表结构) TRUNCATE TABLE student;
DELETE 与 TRUNCATE 的区别:
| 对比项 | DELETE | TRUNCATE |
|---|---|---|
| 是否可带 WHERE | 可以 | 不可以 |
| 是否记录日志 | 逐行记录 | 不逐行记录 |
| 速度 | 较慢 | 很快 |
| 自增 ID 是否重置 | 不重置 | 重置 |
| 是否可回滚(事务内) | 可以 | 不可以 |
4. 事务与 ACID 特性
事务(Transaction)是一组逻辑上不可分割的数据库操作,要么全部成功,要么全部失败。它保证了多个 DML 操作作为一个整体执行,是保证数据一致性的重要机制。
4.1 事务的四大特性(ACID)
| 特性 | 英文 | 说明 |
|---|---|---|
| 原子性 | Atomicity | 事务内的所有操作要么全部提交成功,要么全部回滚,不存在「执行了一半」的状态 |
| 一致性 | Consistency | 事务执行前后,数据库始终处于合法状态,约束(主键、外键、唯一等)始终被满足 |
| 隔离性 | Isolation | 多个事务并发执行时互不干扰,一个事务未提交的修改对其他事务不可见 |
| 持久性 | Durability | 事务一旦提交,其修改将永久保存,即使系统崩溃也不会丢失 |
4.2 事务的基本操作:BEGIN / COMMIT / ROLLBACK
MySQL 中默认每条 DML 语句是自动提交的。如果需要把多条操作放进同一个事务,需要显式开启事务:
-- 开启事务
BEGIN;
-- 执行一组 DML 操作
INSERT INTO student (name, age, email) VALUES ('钱八', 25, 'qianba@example.com');
UPDATE student SET age = age + 1 WHERE id = 1;
-- 全部成功,提交事务
COMMIT;如果事务中途出错,可以使用 ROLLBACK 撤销本事务内所有未提交的修改:
BEGIN;
-- 第一条操作成功
INSERT INTO student (name, age, email) VALUES ('孙九', 26, 'sunjiu@example.com');
-- 第二条操作失败(例如违反唯一约束)
INSERT INTO student (name, age, email) VALUES ('周十', 27, 'sunjiu@example.com');
-- ERROR 1062: Duplicate entry ...
-- 回滚,撤销本事务内的所有修改
ROLLBACK;提示:
COMMIT之后事务结束,修改永久生效;ROLLBACK之后事务结束,修改全部撤销。事务内未提交的修改对其他连接不可见。
4.3 DML 操作在事务中的行为
- INSERT / UPDATE / DELETE 都属于 DML,都可以在事务内执行,并随
COMMIT/ROLLBACK一起生效或撤销; - SELECT 默认不加锁,读取的是已提交的数据(在默认隔离级别下);
- DDL 语句(如 CREATE、ALTER、DROP) 会自动提交当前事务,因此不要在事务中间夹杂 DDL,否则会导致事务提前结束;
- TRUNCATE 属于 DDL,无法在事务内回滚,这也是它与
DELETE的重要区别之一。
5. 综合实战示例
下面通过一个完整的示例,串联本篇文章介绍的核心操作。
5.1 建库建表
-- 创建数据库 CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARSET utf8mb4; USE shop; -- 创建商品表 CREATE TABLE IF NOT EXISTS product ( id INT UNSIGNED AUTO_INCREMENT COMMENT '商品ID', name VARCHAR(100) NOT NULL COMMENT '商品名称', price DECIMAL(10,2) NOT NULL COMMENT '价格', stock INT UNSIGNED DEFAULT 0 COMMENT '库存', status TINYINT DEFAULT 1 COMMENT '状态:1上架 0下架', created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';
5.2 数据操作
-- 插入商品
INSERT INTO product (name, price, stock) VALUES
('手机', 2999.00, 100),
('耳机', 199.00, 500),
('充电器', 59.00, 1000);
-- 查询价格大于 100 的商品,按价格降序
SELECT id, name, price, stock FROM product
WHERE price > 100
ORDER BY price DESC;
-- 给所有商品涨价 10%
UPDATE product SET price = price * 1.1;
-- 删除库存为 0 的商品
DELETE FROM product WHERE stock = 0;5.3 操作流程示意
下面是本示例的完整操作流程:

6. 常见问题与注意事项
6.1 忘记 WHERE 条件
UPDATE 和 DELETE 不带 WHERE 会作用于全表,这是新手最容易犯的错误。建议养成先 SELECT 后 UPDATE/DELETE 的习惯。
6.2 字符集不一致导致乱码
建库、建表时统一使用 utf8mb4,连接串中也应指定 characterEncoding=utf8,避免中文乱码。
6.3 主键与自增
主键建议使用无符号整数自增(INT UNSIGNED AUTO_INCREMENT),避免业务字段作为主键带来的耦合。
6.4 备份意识
6.5 常见 SQL 错误与排查
新手在编写 SQL 时经常遇到各类报错,下面列出 5 个高频错误,并给出错误提示、原因分析、解决方案与正确示例。
错误 1:字段名拼写错误
错误提示示例:
SELECT id, name, age FROM student WHERE ag > 20;
ERROR 1054 (42S22): Unknown column 'ag' in 'where clause'
原因分析: 字段名拼写错误(ag 应为 age),MySQL 无法在表中找到该列。
解决方案: 使用 DESCRIBE student; 或 SHOW COLUMNS FROM student; 查看表结构,确认字段名后再编写 SQL。
正确 SQL:
SELECT id, name, age FROM student WHERE age > 20;
错误 2:数据类型不匹配
错误提示示例:
INSERT INTO student (name, age, email) VALUES ('张三', '二十', 'zhangsan@example.com');
ERROR 1366 (HY000): Incorrect integer value: '二十' for column 'age' at row 1
原因分析: age 字段是整数类型,却传入了字符串 '二十',MySQL 无法完成类型转换。
解决方案: 严格按字段数据类型传值,数字类型传数字,日期类型传合法日期格式。
正确 SQL:
INSERT INTO student (name, age, email) VALUES ('张三', 20, 'zhangsan@example.com');
错误 3:违反唯一约束
错误提示示例:
INSERT INTO student (name, age, email) VALUES ('李四', 22, 'zhangsan@example.com');
ERROR 1062 (23000): Duplicate entry 'zhangsan@example.com' for key 'student.email'
原因分析: email 字段设置了 UNIQUE 唯一约束,插入的邮箱与已有记录重复。
解决方案: 插入前先查询确认该值是否已存在,或使用 INSERT IGNORE、ON DUPLICATE KEY UPDATE 处理冲突。
正确 SQL:
-- 先检查是否已存在
SELECT id FROM student WHERE email = 'zhangsan@example.com';
-- 或使用 INSERT IGNORE 忽略重复
INSERT IGNORE INTO student (name, age, email) VALUES ('李四', 22, 'zhangsan@example.com');错误 4:外键约束失败
错误提示示例:
INSERT INTO student (name, age, dept_id) VALUES ('王五', 21, 999);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
原因分析: dept_id 引用了 dept 表的主键,但 dept 表中不存在 id = 999 的部门记录,外键校验失败。
解决方案: 先确认被引用表中存在对应记录,再插入子表数据;或检查外键字段是否允许为 NULL。
正确 SQL:
-- 先确认部门存在
SELECT id FROM dept WHERE id = 999;
-- 部门存在后再插入
INSERT INTO student (name, age, dept_id) VALUES ('王五', 21, 999);错误 5:字符集不一致导致乱码
错误提示示例:
INSERT INTO student (name) VALUES ('张三');
ERROR 1366 (HY000): Incorrect string value: '\xE5\xBC\xA0\xE4\xB8\x89' for column 'name'
原因分析: 客户端连接字符集与表字符集不一致(如连接使用 latin1,表使用 utf8mb4),中文写入时被截断或报错。
解决方案: 连接时统一指定字符集,建库建表统一使用 utf8mb4。
正确 SQL:
-- 连接时指定字符集 SET NAMES utf8mb4; -- 建表时指定字符集 CREATE TABLE IF NOT EXISTS student ( name VARCHAR(50) NOT NULL COMMENT '姓名' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
执行 DROP、TRUNCATE 等不可逆操作前,务必确认数据已备份。
7. 索引与约束基础
索引与约束是 MySQL 中提升查询性能、保证数据完整性的两大核心机制。本节将介绍常用索引的创建方式、常见约束的作用,以及使用时的注意事项。
7.1 索引的创建
索引用于加速数据检索,可以基于一个或多个字段创建。常用创建方式有两种:CREATE INDEX 和 ALTER TABLE ADD INDEX。
普通索引(单列):
-- 使用 CREATE INDEX 创建普通索引 CREATE INDEX idx_student_name ON student(name); -- 使用 ALTER TABLE 添加普通索引 ALTER TABLE student ADD INDEX idx_student_age (age);
唯一索引(保证字段值不重复):
CREATE UNIQUE INDEX idx_student_email ON student(email); ALTER TABLE student ADD UNIQUE INDEX idx_student_email (email);
联合索引(多个字段组合,遵循最左前缀原则):
CREATE INDEX idx_name_age ON student(name, age); ALTER TABLE student ADD INDEX idx_name_age (name, age);
提示:联合索引中字段的顺序很重要,查询条件应尽量匹配索引的最左前缀,才能充分利用索引。
7.2 常见约束
约束用于保证数据的完整性与一致性,可以在建表时定义,也可以通过 ALTER TABLE 添加。
| 约束类型 | 作用 | 示例 |
|---|---|---|
| 主键约束(PRIMARY KEY) | 唯一标识一行,非空且唯一 | PRIMARY KEY (id) |
| 外键约束(FOREIGN KEY) | 保证表间引用完整性 | FOREIGN KEY (dept_id) REFERENCES dept(id) |
| 唯一约束(UNIQUE) | 保证字段值不重复 | email VARCHAR(100) UNIQUE |
| 非空约束(NOT NULL) | 字段不允许为空 | name VARCHAR(50) NOT NULL |
| 默认值约束(DEFAULT) | 未提供值时使用默认值 | age TINYINT DEFAULT 0 |
在建表时定义约束:
CREATE TABLE IF NOT EXISTS student ( id INT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', name VARCHAR(50) NOT NULL COMMENT '姓名', age TINYINT UNSIGNED DEFAULT 0 COMMENT '年龄', email VARCHAR(100) UNIQUE COMMENT '邮箱', dept_id INT UNSIGNED COMMENT '部门ID', created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (id), CONSTRAINT fk_student_dept FOREIGN KEY (dept_id) REFERENCES dept(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生表';
通过 ALTER TABLE 添加约束:
-- 添加唯一约束 ALTER TABLE student ADD UNIQUE (email); -- 添加外键约束 ALTER TABLE student ADD CONSTRAINT fk_student_dept FOREIGN KEY (dept_id) REFERENCES dept(id);
7.3 索引与约束对比
| 对比项 | 索引 | 约束 |
|---|---|---|
| 主要目的 | 提升查询性能 | 保证数据完整性 |
| 是否影响写入速度 | 会(写入时需维护索引) | 会(写入时需校验) |
| 是否可重复创建 | 可创建多个 | 主键/唯一等有唯一性要求 |
| 是否占用存储空间 | 是(额外索引文件) | 部分约束会隐式创建索引 |
| 典型场景 | 高频查询字段 | 主键、外键、唯一、非空 |
7.4 索引使用注意事项
- 避免索引失效:在索引列上使用函数、隐式类型转换、前置通配符(如
LIKE '%张')都会导致索引失效,应尽量避免。 - 不要过度索引:索引并非越多越好,每个索引都会占用存储空间并拖慢写入速度,只为高频查询字段建立索引。
- 遵循最左前缀原则:使用联合索引时,查询条件应从最左侧字段开始,否则无法命中索引。
- 区分度优先:优先为区分度高(取值多样)的字段建索引,如邮箱、手机号,而不是性别这类取值极少的字段。
- 定期维护:数据频繁增删改后,可考虑重建或优化索引,保持查询效率。
8. 总结
本文系统讲解了 MySQL 的数据定义语言(DDL)与数据操作语言(DML)核心内容:
- DDL:数据库与表的创建、修改、删除,以及常用数据类型;
- DML:数据的插入、查询、更新、删除,以及常用条件与运算符;
- 实战:通过商品表示例串联全部核心操作。
掌握这些基础后,你已经具备了日常开发中最常用的 MySQL 操作能力。下一篇文章我们将继续深入索引、约束与事务等进阶主题,敬请期待。
9. 参考资料与延伸阅读
为了帮助你进一步巩固 MySQL 基础、深入理解底层原理,这里整理了一些官方文档、经典书籍和社区博客,供不同学习阶段参考。
9.1 官方文档
- MySQL 官方文档(https://dev.mysql.com/doc/):最权威、最完整的语法参考。当你对某个 SQL 语句的细节用法、数据类型或函数不确定时,优先查阅官方文档,适合作为日常开发的「字典」随时翻阅。
9.2 经典书籍
- 《高性能 MySQL》(High Performance MySQL):MySQL 领域的经典之作,深入讲解索引原理、查询优化、复制、备份与高可用架构。适合已经掌握基础语法、希望进阶性能调优与架构设计的读者。
- 《MySQL 必知必会》(Sams Teach Yourself MySQL in 10 Minutes):短小精悍的入门读物,以大量短小示例快速覆盖建表、查询、更新等常用操作,适合刚入门、想快速上手的朋友。
9.3 推荐阅读的 CSDN 博客
- MySQL 索引原理与优化实战([占位链接,可替换为具体博客地址]):系统梳理 B+ 树索引结构、最左前缀原则与索引失效场景,配合本文第 7 节内容阅读效果更佳。
- MySQL 事务隔离级别与锁机制详解([占位链接,可替换为具体博客地址]):适合在掌握 DDL/DML 之后,进一步理解并发控制与数据一致性。
- MySQL 慢查询分析与优化案例([占位链接,可替换为具体博客地址]):通过真实案例演示如何定位慢 SQL 并优化,适合进阶学习查询调优。
提示:以上博客链接为占位符,你可以根据实际阅读体验替换为更合适的文章地址。建议优先选择带完整示例、结论清晰的博客,并结合官方文档交叉验证。
到此这篇关于MySQL数据定义与数据操作综合实战示例的文章就介绍到这了,更多相关mysql数据定义与数据操作内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
