✏️ 编辑

MySQL 数据库运维学习笔记(Docker 实操 + Flask 迁移)

创建于 2026-07-06 17:10:05 · 更新于 2026-07-07 09:39:48

MySQL 数据库运维学习笔记(Docker 实操 + Flask 迁移)

日期:2026-07-06
学习方式:Docker 容器实操 + Note Center 从 SQLite 迁移到 MySQL


第一部分:Docker 基础

什么是 Docker?

Docker 是一个容器化平台,把软件连同它的运行环境打包成一个"镜像"(Image),一条命令就能启动。运行起来的镜像叫"容器"(Container)。

类比: 镜像 ≈ ISO 安装盘,容器 ≈ 装好系统的虚拟机。

安装 Docker(OpenCloudOS 9.4)

Bash
# 添加 Docker 官方源
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 安装 Docker 引擎和命令行工具
dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 启动 Docker
systemctl start docker

# 验证
docker --version
docker info

Docker 核心命令

Bash
docker pull 镜像名          # 下载镜像
docker run -d --name 容器名 镜像名   # 后台运行容器
docker ps -a                      # 查看所有容器
docker exec -i 容器名 命令         # 在容器内执行命令
docker images                     # 查看本地镜像列表

端口映射

-p 宿主机端口:容器端口 — 把容器内的端口暴露到宿主机。
例如:-p 3306:3306 让宿主机能通过 127.0.0.1:3306 访问容器里的 MySQL。


第二部分:MySQL 安装与部署(Docker)

Bash
# 拉取 MySQL 8.0 镜像
docker pull mysql:8.0

# 启动 MySQL 容器
docker run -d \
  --name mysql-demo \
  -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD=root123 \
  mysql:8.0

参数说明

参数 含义
-d 后台运行
--name mysql-demo 容器名字
-p 3306:3306 端口映射
-e MYSQL_ROOT_PASSWORD=root123 设置 root 密码

验证连接

Bash
# 查看容器状态
docker ps -a --filter name=mysql-demo(过滤条件) --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"(自定义输出格式。--format 用 Go 模板语法,table 开头表示带表头:\t 是制表符,用来对齐列)

# 在容器内执行 MySQL 命令
docker exec -i mysql-demo mysql -uroot -proot123 -e "SHOW DATABASES;"

docker exec 全链路解析

Bash
docker exec -i mysql-demo mysql -uroot -proot123 -e "SHOW DATABASES;"
分段 作用
docker exec 钻进容器执行命令
-i 保持交互
mysql-demo 目标容器名
mysql 容器里的 MySQL 客户端程序
-uroot -proot123 用 root 登录,密码 root123
-e "SQL语句" 执行一次 SQL 后就退出

整条命令的流程: 宿主机 → Docker 引擎 → 容器 → mysql 客户端 → 连接到容器内的 mysqld → 执行 SQL → 返回结果。

用户疑问:为什么不是用 SELECT * FROM ops_db

因为 SELECT 后面只能跟表名,不能跟数据库名。数据库相当于文件夹,表才是文件。正确写法是 SELECT * FROM ops_db.servers(库名.表名)或先 USE ops_db;SELECT * FROM servers;

用户疑问:输出结果只有列名没有内容?

SHOW DATABASES; 的结果中,information_schemamysqlperformance_schemasys 这些就是内容——它们是 MySQL 自带的系统数据库的名字。列名叫 Database,下面每一行都是一个数据库的实际名称。

用户疑问:ops_db 是什么时候创建的?

在第三课实操中通过 CREATE DATABASE IF NOT EXISTS ops_db 创建的。它是一个练习用的"沙盒"数据库,后续的建表、插数据、权限管理、备份恢复都在里面操作。


第三部分:MySQL 基础概念

MySQL 是什么?

MySQL 是一个数据库管理软件(服务程序叫 mysqld),一直后台运行监听 3306 端口,接收 SQL 命令来读写数据。

对比 SQLite vs MySQL

SQLite MySQL
运行方式 嵌入在程序里,直接读写文件 独立服务程序
如何连接 直接打开 .db 文件 mysql -u用户 -p密码 -h地址
用户权限
多人同时用 不行(写锁) 支持
适用场景 开发环境、小工具 生产环境
端口 3306

层级结构

MySQL 服务器
 └── 数据库(Database)    ← 像 Excel 文件
      └── 表(Table)      ← 像 Excel 里的 Sheet
           ├── 列(Column)← 像 A/B/C 列(字段名)
           └── 行(Row)   ← 一条数据记录

数据类型

类型 说明 示例
INT 整数 cpu_cores INT
VARCHAR(N) 变长字符串,最长 N 字符 hostname VARCHAR(64)
DECIMAL(M,D) 精确小数,M 总位 D 小数位 memory_gb DECIMAL(5,2)
ENUM('a','b') 枚举,只能选列出的值 status ENUM('running','stopped')
DATETIME 日期时间 created_at DATETIME

常用约束

约束 作用
NOT NULL 必填,不能为空
DEFAULT 值 没填时自动补这个值
PRIMARY KEY 主键,唯一标识每一行
AUTO_INCREMENT 自动递增
COMMENT '说明' 字段注释

CRUD 四大操作

SQL
-- 查
SELECT * FROM 库名.表名;
SELECT 列1, 列2 FROM 表名 WHERE 条件;

-- 增
INSERT INTO 表名 (列1, 列2) VALUES (值1, 值2);

-- 改(一定要写 WHERE!)
UPDATE 表名 SET 列=新值 WHERE 条件;

-- 删(一定要写 WHERE!)
DELETE FROM 表名 WHERE 条件;

运维金句: 没有 WHERE 的 UPDATE 和 DELETE 就是删库跑路。


第四部分:用户权限管理

为什么不能都用 root?

生产环境需要最小权限原则——每个用户只给够用的权限。

用户由两部分组成

SQL
'用户名'@'主机'
写法 含义
'u'@'localhost' 只能从本机连
'u'@'%' 任何地方都能连
'u'@'192.168.1.%' 只允许内网段

常用命令

SQL
CREATE USER '用户名'@'主机' IDENTIFIED BY '密码';
GRANT 权限 ON 库.表 TO '用户'@'主机';
SHOW GRANTS FOR '用户'@'主机';

实操:创建只读用户

SQL
CREATE USER 'dev_zhou'@'localhost' IDENTIFIED BY 'Monitor@2024';
GRANT SELECT ON ops_db.* TO 'monitor'@'localhost';
-- 验证:可以 SELECT,但 DELETE 被拒绝
加权限
GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'dev_zhou'@'localhost';


第五部分:mysqldump 备份与恢复

备份

Bash
docker exec mysql-demo mysqldump -uroot -proot123 ops_db > backup.sql

备份文件的内容

备份文件包含 CREATE TABLE(建表结构)+ INSERT INTO(插数据)的 SQL 命令。

恢复

Bash
docker exec -i mysql-demo mysql -uroot -proot123 ops_db < backup.sql

备份 vs 恢复对比

>(备份) <(恢复)
方向 数据库 → 文件 文件 → 数据库
程序 mysqldump mysql 客户端

第六部分:慢查询排查与索引优化

为什么 SQL 会慢?

根本原因是 MySQL 需要扫描太多数据才能找到你要的结果。

索引是什么?

索引就像字典的拼音目录——排好序的数据结构,让 MySQL 能用二分查找快速定位,而不是逐行扫描全表。

EXPLAIN 只看三个指标

docker exec mysql-demo mysql -uroot -proot123 -e "USE ops_db; DESC test_slow; SHOW INDEX FROM test_slow;" 2>&1
| 指标 | 好的信号 | 坏的信号 |
|------|---------|---------|
| type | ref(索引查找) | ALL(全表扫描) |
| rows | 个位数 | 几万以上行数 |
| key | 有索引名 | NULL(没用索引) |

加索引

SQL
CREATE INDEX idx_name ON 表名 (列名);
-- 只给经常出现在 WHERE 条件里的列加索引
EXPLAIN SELECT * FROM test_slow WHERE username = 'user_100';

慢查询日志

SQL
docker exec mysql-demo mysql -uroot -proot123 -e "SHOW VARIABLES LIKE 'slow_query_log_file'; SHOW VARIABLES LIKE 'slow_query_log'; SHOW VARIABLES LIKE 'long_query_time';" 2>&1

docker exec mysql-demo cat /var/lib/mysql/ff129f65a5fa-slow.log | tail -50(MySQL 跑在 Docker 容器里,宿主机 /var/lib/mysql 下没有文件)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 2;

第七部分:Flask + MySQL 迁移

整体流程

① 在 MySQL 里创建 note_center 库和用户 nc_app
② pip install pymysql(Python 连 MySQL 的驱动)
③ 改 config.py(加 MySQL 连接配置)
④ 改 database.py(pymysql 替换 sqlite3,建表语句适配 MySQL 语法)
⑤ 改 models.py(? → %s,FTS5 → FULLTEXT,NULLS LAST 处理)
⑥ 改 monitor.py + routes.py + app.py
⑦ 启动测试

核心语法差异

SQLite MySQL
INTEGER PRIMARY KEY AUTOINCREMENT INT AUTO_INCREMENT PRIMARY KEY
REAL DOUBLE
TEXT NOT NULL DEFAULT '' 不支持,改为 VARCHAR 或无 DEFAULT
INSERT OR IGNORE INSERT IGNORE
ORDER BY col ASC NULLS LAST ORDER BY (col IS NULL) ASC, col ASC
? 参数占位符 %s 参数占位符

迁移前后

改之前:Note Center → SQLite 文件 (data/notes.db)
改之后:Note Center → MySQL 8.0 容器 (mysql-demo:3306)

启动顺序(机器重启后)

Bash
docker start mysql-demo    # 先启动 MySQL
python3 app.py             # 再启动 Note Center

学习收获总结

领域 掌握内容
Docker 安装、镜像/容器概念、核心命令、端口映射
MySQL 基础 数据库结构、数据类型、约束、CRUD
MySQL 权限 创建用户、授权、最小权限原则
MySQL 备份 mysqldump 备份与恢复
索引优化 EXPLAIN 分析、CREATE INDEX、慢查询日志
项目迁移 SQLite → MySQL 全流程、语法差异处理