这是《MySQL 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 学习 MySQL 最忌讳“只看不做”。本章会搭建一个可反复破坏、可随时重建的实验环境,并初始化一个贯穿全书的小型电商订单库。推荐使用 Docker 版本,因为它能在几分钟内得到干净的 MySQL 8.0 实例。
2.1 安装方式选择
| 方式 | 适合场景 | 优点 | 缺点 |
|---|---|---|---|
| Docker | 本地学习、自动化测试 | 干净、可重复、可多实例 | 需要理解容器和挂载 |
| MySQL Installer | Windows 桌面学习 | 图形化安装 | 环境残留较多 |
| apt / yum | Linux 服务器 | 贴近生产 | 版本取决于发行源 |
| MySQL Shell + 远程库 | 只有学习环境 | 本地免安装 | 无法测试本地运维操作 |
| 云数据库 | 快速体验生产能力 | 备份和高可用完善 | 成本和权限受限 |
本书默认环境:
- MySQL 8.0 或 8.4;
- 操作系统:macOS / Windows / Linux 均可;
- 客户端:
mysqlCLI、MySQL Shell、DBeaver、DataGrip 任选; - 网络模式:本机学习,端口默认
3306。
MySQL 8.0 和 8.4 的主要差异会在涉及身份认证、默认排序规则、并行能力时单独说明。没有特别说明时,示例默认面向 MySQL 8.0。
2.2 使用 Docker 启动 MySQL
创建工作目录:
mkdir C:\mysql-lab
cd C:\mysql-lab
启动 MySQL 8.0:
docker run -d `
--name mysql-lab `
-p 3306:3306 `
-e MYSQL_ROOT_PASSWORD=Root123456! `
-e MYSQL_DATABASE=shop `
-e TZ=Asia/Shanghai `
-v C:\mysql-lab\data:/var/lib/mysql `
-v C:\mysql-lab\conf:/etc/mysql/conf.d `
mysql:8.0
Linux / macOS 使用普通续行符:
docker run -d \
--name mysql-lab \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD='Root123456!' \
-e MYSQL_DATABASE=shop \
-e TZ=Asia/Shanghai \
-v "$PWD/data:/var/lib/mysql" \
-v "$PWD/conf:/etc/mysql/conf.d" \
mysql:8.0
参数说明:
| 参数 | 说明 |
|---|---|
--name mysql-lab |
容器名,方便管理 |
-p 3306:3306 |
宿主机端口映射到容器端口 |
MYSQL_ROOT_PASSWORD |
root 初始密码,仅用于本地实验 |
MYSQL_DATABASE=shop |
首次启动时创建 shop 库 |
TZ=Asia/Shanghai |
容器时区 |
| 数据挂载 | 数据保存在宿主机,容器删除后仍可恢复 |
| 配置挂载 | 自定义配置文件会自动加载 |
生产中不要把 root 密码写在命令行或脚本里,应使用密钥管理系统、云托管 Secret 或受控的配置中心。
2.3 初始化配置文件
创建 conf/mysql.cnf:
[mysqld]
port = 3306
character-set-server = utf8mb4
collation-server = utf8mb4_0900_ai_ci
default-time-zone = '+08:00'
max_connections = 500
wait_timeout = 28800
interactive_timeout = 28800
max_allowed_packet = 64M
innodb_buffer_pool_size = 512M
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table = 1
innodb_print_all_deadlocks = 1
slow_query_log = 1
slow_query_log_file = /var/lib/mysql/slow.log
long_query_time = 0.5
log_queries_not_using_indexes = 1
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
重启容器使配置生效:
docker restart mysql-lab
查看配置是否生效:
SHOW VARIABLES WHERE Variable_name IN (
'version',
'character_set_server',
'collation_server',
'innodb_buffer_pool_size',
'innodb_flush_log_at_trx_commit',
'slow_query_log',
'long_query_time'
);
几个关键配置的取舍:
| 配置 | 学习环境建议 | 生产建议 |
|---|---|---|
innodb_buffer_pool_size |
512M 到 2G | 专用机器可用内存的 50% 到 70% |
innodb_flush_log_at_trx_commit |
1 | 金融和订单主库保持 1 |
sync_binlog |
1 | 主库通常保持 1 |
slow_query_log |
开启 | 开启并接入采集 |
log_queries_not_using_indexes |
开启 | 谨慎开启,避免日志量过大 |
2.4 连接 MySQL
进入容器:
docker exec -it mysql-lab mysql -uroot -p
输入密码后看到 mysql> 提示即连接成功。
查看版本和当前时间:
SELECT VERSION(), CURRENT_TIMESTAMP(), @@server_timezone;
SHOW DATABASES;
使用 shop 库:
USE shop;
SELECT DATABASE();
常用客户端命令:
| 命令 | 说明 |
|---|---|
SHOW DATABASES; |
查看数据库 |
USE shop; |
切换数据库 |
SHOW TABLES; |
查看当前库的表 |
SHOW CREATE TABLE orders\G |
查看建表语句 |
STATUS; |
查看连接和服务状态 |
EXIT; |
退出客户端 |
2.5 创建学习账号
学习阶段就应该避免长期使用 root。创建一个只有 shop 库权限的账号:
CREATE USER 'shop_app'@'%' IDENTIFIED BY 'App123456!';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE TEMPORARY TABLES
ON shop.* TO 'shop_app'@'%';
FLUSH PRIVILEGES;
创建只读账号:
CREATE USER 'shop_ro'@'%' IDENTIFIED BY 'Read123456!';
GRANT SELECT ON shop.* TO 'shop_ro'@'%';
查看权限:
SHOW GRANTS FOR 'shop_app'@'%';
SHOW GRANTS FOR 'shop_ro'@'%';
本地实验可以用 % 作为客户端来源。生产账号应尽量绑定网段或主机,例如:
CREATE USER 'shop_app'@'10.0.%.%' IDENTIFIED BY 'strong-password';
2.6 初始化实验表
在 shop 库执行以下脚本。这套表会在后续章节反复使用。
CREATE TABLE users (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户ID',
username VARCHAR(32) NOT NULL COMMENT '登录名',
nickname VARCHAR(64) NOT NULL COMMENT '昵称',
mobile VARCHAR(20) NOT NULL COMMENT '手机号',
status TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态:1正常,2禁用',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_username (username),
UNIQUE KEY uk_mobile (mobile),
KEY idx_status_created (status, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
COMMENT='用户表';
CREATE TABLE merchants (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '商户ID',
merchant_name VARCHAR(64) NOT NULL COMMENT '商户名称',
city_code VARCHAR(16) NOT NULL COMMENT '城市编码',
status TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态:1营业,2停业',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_merchant_name (merchant_name),
KEY idx_city_status (city_code, status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
COMMENT='商户表';
CREATE TABLE products (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '商品ID',
merchant_id BIGINT UNSIGNED NOT NULL COMMENT '商户ID',
product_name VARCHAR(128) NOT NULL COMMENT '商品名',
category VARCHAR(32) NOT NULL COMMENT '类目',
price DECIMAL(12, 2) NOT NULL COMMENT '售价',
stock INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '库存',
status TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态:1上架,2下架',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
KEY idx_merchant_status (merchant_id, status),
KEY idx_category_price (category, price)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
COMMENT='商品表';
CREATE TABLE orders (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '订单ID',
order_no VARCHAR(32) NOT NULL COMMENT '业务订单号',
user_id BIGINT UNSIGNED NOT NULL COMMENT '用户ID',
merchant_id BIGINT UNSIGNED NOT NULL COMMENT '商户ID',
status VARCHAR(16) NOT NULL DEFAULT 'CREATED' COMMENT '订单状态',
total_amount DECIMAL(12, 2) NOT NULL DEFAULT 0.00 COMMENT '订单总金额',
paid_amount DECIMAL(12, 2) NOT NULL DEFAULT 0.00 COMMENT '实付金额',
currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '币种',
paid_at DATETIME(3) NULL COMMENT '支付时间',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_order_no (order_no),
KEY idx_user_created (user_id, created_at),
KEY idx_merchant_status_created (merchant_id, status, created_at),
KEY idx_status_created (status, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
COMMENT='订单主表';
CREATE TABLE order_items (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '明细ID',
order_id BIGINT UNSIGNED NOT NULL COMMENT '订单ID',
product_id BIGINT UNSIGNED NOT NULL COMMENT '商品ID',
product_name VARCHAR(128) NOT NULL COMMENT '商品快照',
unit_price DECIMAL(12, 2) NOT NULL COMMENT '成交单价',
quantity INT UNSIGNED NOT NULL COMMENT '数量',
subtotal DECIMAL(12, 2) NOT NULL COMMENT '小计',
PRIMARY KEY (id),
UNIQUE KEY uk_order_product (order_id, product_id),
KEY idx_product (product_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
COMMENT='订单明细表';
确认表创建成功:
SHOW TABLES;
SHOW CREATE TABLE orders\G
2.7 插入基础数据
INSERT INTO users (username, nickname, mobile) VALUES
('alice', 'Alice', '13800000001'),
('bob', 'Bob', '13800000002'),
('carol', 'Carol', '13800000003');
INSERT INTO merchants (merchant_name, city_code) VALUES
('Fresh Store', '010'),
('Book Store', '021'),
('Digital Store', '0755');
INSERT INTO products
(merchant_id, product_name, category, price, stock) VALUES
(1, 'Apple', 'FRUIT', 8.50, 100),
(1, 'Milk', 'FOOD', 12.00, 80),
(2, 'MySQL Book', 'BOOK', 79.00, 50),
(3, 'Keyboard', 'DIGITAL', 399.00, 30),
(3, 'Mouse', 'DIGITAL', 129.00, 60);
验证:
SELECT * FROM users;
SELECT * FROM products;
2.8 常用管理命令
查看进程列表:
SHOW PROCESSLIST;
查看 InnoDB 状态:
SHOW ENGINE INNODB STATUS\G
查看表状态:
SHOW TABLE STATUS FROM shop LIKE 'orders'\G
查看错误日志路径:
SHOW VARIABLES LIKE 'log_error';
在容器内查看日志:
docker exec -it mysql-lab bash
tail -n 100 /var/lib/mysql/*.err
2.9 常见安装问题
2.9.1 客户端无法连接
常见原因:
- 容器未启动;
- 宿主机端口被占用;
- MySQL 账号来源限制不匹配;
- 云安全组未放行;
- 密码错误。
排查命令:
docker ps --filter name=mysql-lab
docker logs --tail 100 mysql-lab
2.9.2 认证插件错误
老客户端连接 MySQL 8.0 时可能提示认证插件不支持。可以升级客户端,或为学习账号指定 mysql_native_password:
ALTER USER 'shop_app'@'%' IDENTIFIED WITH mysql_native_password BY 'App123456!';
MySQL 8.4 默认禁用了 mysql_native_password,需要先启用插件后才能使用。生产环境更推荐直接升级客户端。
2.9.3 时区不一致
查看时区:
SELECT @@global.time_zone, @@session.time_zone, NOW();
如果 JDBC 连接出现时间差,在连接串中显式声明:
jdbc:mysql://127.0.0.1:3306/shop?serverTimezone=Asia/Shanghai
2.9.4 字符集乱码
确认字符集:
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
统一原则:
- 服务端使用
utf8mb4; - 表和列显式指定字符集;
- 客户端连接使用
utf8mb4; - 应用源码文件使用 UTF-8。
2.10 数据导入导出
导出表结构和数据:
mysqldump -h127.0.0.1 -uroot -p \
--single-transaction --routines --triggers \
shop > shop_backup.sql
恢复:
mysql -h127.0.0.1 -uroot -p shop < shop_backup.sql
只导出结构:
mysqldump -h127.0.0.1 -uroot -p --no-data shop > shop_schema.sql
mysqldump 会在备份恢复章节详细展开。这里只需要掌握基本用法,并记住 --single-transaction 可以避免 InnoDB 备份期间长时间锁表。
2.11 环境管理
停止和启动:
docker stop mysql-lab
docker start mysql-lab
删除容器:
docker rm -f mysql-lab
如果想彻底重置实验环境,可以同时删除宿主机挂载的 data 目录。生产环境绝对不能这样做,删除数据目录前必须确认备份可恢复。
本章小结
一个可控的实验环境是学习 MySQL 的基础。Docker 提供了干净、可重复的启动方式;合理配置字符集、时区、慢日志和 InnoDB 参数能让后续实验更贴近生产。学习账号应与 root 分离,实验表应包含主键、唯一约束和常用复合索引。遇到连接问题时应依次排查容器状态、端口、账号来源、密码和网络策略。
思考题
- 为什么学习环境也应该创建普通账号,而不是长期使用 root?
innodb_buffer_pool_size为什么通常是专用数据库服务器最重要的参数之一?utf8mb4和历史utf8有什么区别?mysqldump --single-transaction对 InnoDB 备份有什么意义?- 为你的学习环境设计一套“初始化、备份、重置”脚本。