MySQLNotes

第 02 章:环境搭建

zjc 于 2026-01-02 发布

这是《MySQL 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 学习 MySQL 最忌讳“只看不做”。本章会搭建一个可反复破坏、可随时重建的实验环境,并初始化一个贯穿全书的小型电商订单库。推荐使用 Docker 版本,因为它能在几分钟内得到干净的 MySQL 8.0 实例。

2.1 安装方式选择

方式 适合场景 优点 缺点
Docker 本地学习、自动化测试 干净、可重复、可多实例 需要理解容器和挂载
MySQL Installer Windows 桌面学习 图形化安装 环境残留较多
apt / yum Linux 服务器 贴近生产 版本取决于发行源
MySQL Shell + 远程库 只有学习环境 本地免安装 无法测试本地运维操作
云数据库 快速体验生产能力 备份和高可用完善 成本和权限受限

本书默认环境:

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 客户端无法连接

常见原因:

  1. 容器未启动;
  2. 宿主机端口被占用;
  3. MySQL 账号来源限制不匹配;
  4. 云安全组未放行;
  5. 密码错误。

排查命令:

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%';

统一原则:

  1. 服务端使用 utf8mb4
  2. 表和列显式指定字符集;
  3. 客户端连接使用 utf8mb4
  4. 应用源码文件使用 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 分离,实验表应包含主键、唯一约束和常用复合索引。遇到连接问题时应依次排查容器状态、端口、账号来源、密码和网络策略。

思考题

  1. 为什么学习环境也应该创建普通账号,而不是长期使用 root?
  2. innodb_buffer_pool_size 为什么通常是专用数据库服务器最重要的参数之一?
  3. utf8mb4 和历史 utf8 有什么区别?
  4. mysqldump --single-transaction 对 InnoDB 备份有什么意义?
  5. 为你的学习环境设计一套“初始化、备份、重置”脚本。