init-databases.sh 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
  4. sql_path="${project_root}/database/mysql.sql"
  5. container_name="${1:-${ZBT_MYSQL_CONTAINER:-zhibaotong-mysql}}"
  6. container_sql_path="/tmp/zbt-init.sql"
  7. [[ -f "$sql_path" ]] || {
  8. echo "错误:缺少数据库快照 $sql_path" >&2
  9. exit 1
  10. }
  11. command -v docker >/dev/null 2>&1 || {
  12. echo "错误:未找到 Docker 命令,请先安装并启动 Docker Desktop。" >&2
  13. exit 1
  14. }
  15. docker inspect "$container_name" >/dev/null 2>&1 || {
  16. echo "错误:未找到 MySQL 容器 $container_name,可将实际容器名作为第一个参数传入。" >&2
  17. exit 1
  18. }
  19. if [[ "$(docker inspect --format '{{.State.Running}}' "$container_name")" != "true" ]]; then
  20. docker start "$container_name" >/dev/null
  21. fi
  22. # 首次创建 MySQL 容器时会经历“临时实例初始化 -> 正式实例启动”。
  23. # 要求连续多次响应,避免命令落在两次启动之间。
  24. ready=false
  25. consecutive_successes=0
  26. for _ in $(seq 1 90); do
  27. if docker exec "$container_name" sh -c 'mysqladmin ping -uroot -p"$MYSQL_ROOT_PASSWORD" --silent >/dev/null 2>&1'; then
  28. consecutive_successes=$((consecutive_successes + 1))
  29. if (( consecutive_successes >= 5 )); then
  30. ready=true
  31. break
  32. fi
  33. else
  34. consecutive_successes=0
  35. fi
  36. sleep 1
  37. done
  38. if [[ "$ready" != "true" ]]; then
  39. echo "MySQL 容器 $container_name 在 90 秒内未就绪。" >&2
  40. exit 1
  41. fi
  42. cleanup() {
  43. docker exec "$container_name" rm -f "$container_sql_path" >/dev/null 2>&1 || true
  44. }
  45. trap cleanup EXIT
  46. docker cp "$sql_path" "${container_name}:${container_sql_path}"
  47. docker exec "$container_name" sh -c \
  48. 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" --default-character-set=utf8mb4 < /tmp/zbt-init.sql'
  49. echo "第二阶段 MySQL 数据初始化完成。"