4. MySQL 8.0 容器化部署:拉取镜像、编写 docker-compose 服务、端口映射、数据持久化(volume)、字符集设置

在支付订单系统的本地开发环境中,MySQL 作为核心关系型数据库,承担着订单表、支付流水表、账户余额表等关键数据的存储。采用 Docker 容器化部署 MySQL 8.0,可以快速搭建与生产环境一致的数据库服务,避免因操作系统差异导致的兼容性问题。本节将详细讲解从镜像拉取到完整配置的每一步操作。

4.1 拉取 MySQL 8.0 官方镜像

首先,从 Docker Hub 拉取 MySQL 8.0 的官方镜像。建议指定具体的小版本号(如 8.0.32)以确保环境可复现,避免因镜像更新导致行为变化。

# 拉取 MySQL 8.0.32 版本
docker pull mysql:8.0.32

# 验证镜像是否拉取成功
docker images | grep mysql
版本选择建议: 支付系统对数据一致性要求极高,建议避免使用 latest 标签。选择 8.0.x 系列中经过充分验证的稳定版本,如 8.0.32 或 8.0.35。

4.2 编写 docker-compose.yml 服务定义

使用 Docker Compose 可以统一管理 MySQL 容器的配置。以下是一个面向支付订单系统的完整 docker-compose.yml 示例,包含端口映射、数据持久化、字符集设置等关键配置。

version: '3.8'

services:
  mysql-payment:
    image: mysql:8.0.32
    container_name: payment-mysql
    restart: unless-stopped
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: Payment@2024!
      MYSQL_DATABASE: payment_order
      MYSQL_USER: payment_app
      MYSQL_PASSWORD: App@2024!
    volumes:
      - mysql_data:/var/lib/mysql
      - ./mysql-init:/docker-entrypoint-initdb.d
      - ./mysql-config:/etc/mysql/conf.d
    command: >
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
      --default-authentication-plugin=mysql_native_password
      --max_connections=200
      --innodb_buffer_pool_size=512M
      --binlog_format=ROW
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  mysql_data:
    driver: local

4.3 端口映射与网络规划

端口映射是容器化部署的基础配置。MySQL 默认监听 3306 端口,通过 ports 指令将宿主机端口映射到容器端口。在支付系统中,通常需要规划多个数据库实例(如订单库、支付库、日志库),因此端口映射需要避免冲突。

场景 宿主机端口 容器端口 说明
单实例开发 3306 3306 直接映射,简单易用
多实例开发 3307 3306 订单库实例
多实例开发 3308 3306 支付流水库实例
生产环境 3306 3306 通过防火墙限制访问
端口冲突排查: 如果宿主机 3306 端口已被占用(如本地已安装 MySQL),启动容器会报错。此时可执行 sudo lsof -i :3306 查看占用进程,或修改宿主机映射端口为 3307 等未占用端口。

4.4 数据持久化:Volume 挂载策略

容器默认存储的数据在容器删除后会丢失,这对支付系统来说是不可接受的。通过 Docker Volume 将 MySQL 数据目录挂载到宿主机,可以确保数据持久化。同时,初始化脚本和自定义配置文件的挂载也是关键环节。

MySQL 容器 Volume 挂载架构 宿主机文件系统 mysql_data /var/lib/docker/volumes/ ./mysql-init 初始化 SQL 脚本 ./mysql-config 自定义 my.cnf MySQL 容器 (payment-mysql) /var/lib/mysql /docker-entrypoint-initdb.d /etc/mysql/conf.d 数据文件持久化 | 首次启动自动执行建表脚本 | 覆盖默认字符集配置
挂载策略要点:
  • mysql_data(命名卷): 由 Docker 自动管理,存放路径为 /var/lib/docker/volumes/,适合生产环境,备份时使用 docker run --rm -v mysql_data:/data alpine tar -czf backup.tar.gz /data。
  • ./mysql-init(绑定挂载): 存放建表、初始化数据的 SQL 脚本,容器首次启动时自动执行。支付系统可在此创建订单表、支付流水表、账户表等核心表结构。
  • ./mysql-config(绑定挂载): 存放自定义的 my.cnf 配置文件,用于覆盖默认字符集、连接数、缓冲池大小等参数。

4.5 字符集设置:utf8mb4 与排序规则

支付订单系统需要存储多语言字符(如用户姓名、商品描述)以及 Emoji 表情(如支付成功通知中的图标),因此必须使用 utf8mb4 字符集。MySQL 8.0 默认字符集已改为 utf8mb4,但显式配置可以确保一致性。

在 docker-compose.yml 的 command 指令中,通过 --character-set-server=utf8mb4 和 --collation-server=utf8mb4_unicode_ci 设置服务端字符集。此外,还可以通过自定义配置文件进行更精细的控制。

# 创建自定义配置文件 ./mysql-config/custom.cnf
[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init-connect = 'SET NAMES utf8mb4'

# 支付系统推荐参数
innodb_default_row_format = DYNAMIC
skip-character-set-client-handshake
字符集配置项 推荐值 说明
character-set-server utf8mb4 服务端默认字符集,支持 4 字节 UTF-8
collation-server utf8mb4_unicode_ci 基于 Unicode 的排序规则,支持多语言排序
init-connect SET NAMES utf8mb4 客户端连接时自动设置字符集
innodb_default_row_format DYNAMIC 支持 utf8mb4 的变长列存储,避免索引过长
字符集陷阱: 如果数据库、表、列的字符集不一致,可能导致数据截断或乱码。建议在创建数据库时显式指定字符集:CREATE DATABASE payment_order CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;。同时,应用层的 JDBC 连接字符串也要添加 characterEncoding=utf8mb4 参数。

4.6 启动与验证

完成 docker-compose.yml 编写后,通过以下命令启动 MySQL 容器并验证配置是否生效。

# 启动容器(后台运行)
docker-compose up -d

# 查看容器运行状态
docker-compose ps

# 进入容器内部验证字符集
docker exec -it payment-mysql mysql -uroot -p'Payment@2024!'

# 在 MySQL 命令行中执行
mysql> SHOW VARIABLES LIKE 'character_set_server';
mysql> SHOW VARIABLES LIKE 'collation_server';
mysql> SHOW VARIABLES LIKE 'character_set_database';

# 验证数据持久化:停止并删除容器后,数据是否保留
docker-compose down
docker-compose up -d
# 检查之前创建的数据库和表是否仍然存在
健康检查: docker-compose.yml 中配置了 healthcheck,可以通过 docker inspect payment-mysql --format='{{json .State.Health}}' 查看容器健康状态。在支付系统中,建议在应用启动前等待 MySQL 健康检查通过,避免连接失败。

4.7 支付系统初始化脚本示例

在 ./mysql-init 目录下创建初始化脚本,容器首次启动时会自动执行。以下是一个支付订单系统的建表示例。

-- ./mysql-init/01_create_tables.sql
USE payment_order;

-- 订单主表
CREATE TABLE IF NOT EXISTS t_order (
    order_id BIGINT AUTO_INCREMENT PRIMARY KEY,
    order_no VARCHAR(64) NOT NULL COMMENT '订单号',
    user_id BIGINT NOT NULL COMMENT '用户ID',
    total_amount DECIMAL(18,2) NOT NULL COMMENT '订单总金额',
    status TINYINT NOT NULL DEFAULT 0 COMMENT '订单状态:0-待支付 1-已支付 2-已取消',
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uk_order_no (order_no),
    INDEX idx_user_id (user_id),
    INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单主表';

-- 支付流水表
CREATE TABLE IF NOT EXISTS t_payment_transaction (
    trans_id BIGINT AUTO_INCREMENT PRIMARY KEY,
    order_no VARCHAR(64) NOT NULL COMMENT '关联订单号',
    trans_no VARCHAR(64) NOT NULL COMMENT '支付流水号',
    pay_amount DECIMAL(18,2) NOT NULL COMMENT '支付金额',
    pay_channel VARCHAR(32) NOT NULL COMMENT '支付渠道:WECHAT- ALIPAY-支付宝',
    status TINYINT NOT NULL DEFAULT 0 COMMENT '流水状态:0-处理中 1-成功 2-失败',
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_trans_no (trans_no),
    INDEX idx_order_no (order_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='支付流水表';

通过以上步骤,一个面向支付订单系统的 MySQL 8.0 容器化环境就搭建完成了。该环境具备数据持久化、正确的字符集配置、以及自动初始化的表结构,为后续的本地调试和功能开发提供了稳定可靠的数据库基础。