本地開發完成後,將資料庫遷移至生產/測試伺服器是標準流程。本文提供兩種主流工具(phpMyAdmin、MySQL-Front)的圖文級操作步驟,涵蓋備份、清空目標庫、匯入、驗證、權限、字符集、大檔案分割等關鍵細節,確保遷移零差錯。
utf8mb4 / utf8mb4_unicode_cihttps://localhost/phpmyadmin)ADD DROP TABLE、IF NOT EXISTS、AUTO_INCREMENTINSERT 模式選 INSERT IGNORE 或 REPLACE(視業務)utf8mb4db_name.sql.gz.sql.gz 檔案utf8mb4upload_max_filesize、post_max_size、max_execution_time、memory_limitzcat db.sql.gz | split -l 50000 - db_part_ → 依次匯入分割檔# 單庫
mysqldump -h localhost -u root -p --single-transaction --routines --triggers --events \
--default-character-set=utf8mb4 --hex-blob \
db_name | gzip > db_name_$(date +%F).sql.gz
# 多庫
mysqldump -h localhost -u root -p --databases db1 db2 ... | gzip > multi_db.sql.gz
關鍵參數:--single-transaction(InnoDB 一致性備份不鎖表)、--hex-blob(二進位欄位安全)、--routines/triggers/events(完整物件)。
# 解壓並匯入
zcat db_name.sql.gz | mysql -h remote_host -u user -p -D target_db --default-character-set=utf8mb4
# 或先解壓再匯入(大檔案建議)
gunzip -c db_name.sql.gz | mysql -h remote_host -u user -p target_db
# 安裝 pv (Pipe Viewer)
apt-get install pv
zcat db_name.sql.gz | pv | mysql -h remote_host -u user -p target_db
| 檢查項 | SQL/命令 | 預期結果 |
|---|---|---|
| 表數量一致 | SHOW TABLES; | 本地/遠端表數相同 |
| 行數一致 | SELECT TABLE_NAME, TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA='db'; | 核心表行數相同(TABLE_ROWS 為估算值,精確用 COUNT(*)) |
| 字符集正確 | SHOW CREATE TABLE t;\nSHOW VARIABLES LIKE 'character_set%'; | 表/庫/連線均為 utf8mb4 |
| 自增值正確 | SHOW TABLE STATUS LIKE 't'; | Auto_increment 合理 |
| 視圖/存儲過程/觸發器 | SHOW FULL TABLES WHERE Table_type='VIEW'; | 物件完整遷移 |
| 應用連線測試 | 修改配置指向遠端,跑測試套件/手動冒煙 | 讀寫正常 |
| 問題 | 原因 | 解決 |
|---|---|---|
| Unknown collation: utf8mb4_0900_ai_ci | MySQL 8.0 預設校對規則,5.7 不支援 | 匯出時指定 --default-character-set=utf8mb4,或匯入前 sed 替換校對規則 |
| ERROR 1231 (42000): Variable 'sql_mode' can't be set | 版本差異導致 sql_mode 不相容 | 匯出檔開頭 SET SQL_MODE=... 註釋/刪除,或目標庫調整 sql_mode |
| 外鍵約束失敗 | 匯入順序導致父表未建立 | 匯出含 SET FOREIGN_KEY_CHECKS=0;,或手動在匯入 SQL 前後加上 |
| 中文亂碼 | 連線字符集不一致 | 確保 SET NAMES utf8mb4、資料庫/表/欄位均為 utf8mb4 |
| 最大包體超限 | max_allowed_packet 過小 | 目標庫 SET GLOBAL max_allowed_packet=1073741824; (1GB) |
#!/bin/bash
# migrate_db.sh
set -euo pipefail
LOCAL_HOST="127.0.0.1"
LOCAL_USER="root"
LOCAL_PASS="local_pass"
LOCAL_DB="myapp"
REMOTE_HOST="db.prod.example.com"
REMOTE_USER="app_user"
REMOTE_PASS="prod_pass"
REMOTE_DB="myapp"
DUMP_FILE="/tmp/${LOCAL_DB}_$(date +%s).sql.gz"
echo "📦 Dumping local database..."
mysqldump -h "$LOCAL_HOST" -u "$LOCAL_USER" -p"$LOCAL_PASS" \
--single-transaction --routines --triggers --events \
--default-character-set=utf8mb4 --hex-blob \
"$LOCAL_DB" | gzip > "$DUMP_FILE"
echo "🚀 Importing to remote..."
zcat "$DUMP_FILE" | mysql -h "$REMOTE_HOST" -u "$REMOTE_USER" -p"$REMOTE_PASS" \
--default-character-set=utf8mb4 "$REMOTE_DB"
echo "✅ Verifying table count..."
LOCAL_CNT=$(mysql -h "$LOCAL_HOST" -u "$LOCAL_USER" -p"$LOCAL_PASS" -N -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$LOCAL_DB';")
REMOTE_CNT=$(mysql -h "$REMOTE_HOST" -u "$REMOTE_USER" -p"$REMOTE_PASS" -N -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$REMOTE_DB';")
if [[ "$LOCAL_CNT" == "$REMOTE_CNT" ]]; then
echo "✅ Table count match: $LOCAL_CNT"
else
echo "❌ Table count mismatch: local=$LOCAL_CNT remote=$REMOTE_CNT"
exit 1
fi
rm -f "$DUMP_FILE"
echo "🎉 Migration completed!"
資料庫遷移看似簡單,細節決定成敗。建立標準化 SOP、自動化腳本、驗證清單,才能在每次發布中做到「無感遷移、零故障」。








