统一开发环境使用 MySQL

This commit is contained in:
yml2213
2026-07-25 11:01:57 +08:00
parent 10f298b4e1
commit 73ec12bcbc
4 changed files with 117 additions and 11 deletions
+16 -1
View File
@@ -21,11 +21,26 @@ APP_PORT=8000
# Docker 构建镜像源(服务器保持 true;本地测试可改为 false) # Docker 构建镜像源(服务器保持 true;本地测试可改为 false)
USE_CHINA_MIRRORS=true USE_CHINA_MIRRORS=true
# MySQL 配置(生产环境必须设置密码;MySQL 不映射宿主端口 # MySQL 配置(生产环境必须设置密码;默认只映射宿主机 127.0.0.1,供本地 dev.sh 使用
# 服务器部署默认使用国内镜像;./dev.sh 默认临时改用 mysql:8.4,避免本地测试走国内镜像。
# MYSQL_IMAGE=docker.m.daocloud.io/library/mysql:8.4
MYSQL_DATABASE=douyu_login MYSQL_DATABASE=douyu_login
MYSQL_USER=douyu_login MYSQL_USER=douyu_login
MYSQL_PASSWORD= MYSQL_PASSWORD=
MYSQL_ROOT_PASSWORD= MYSQL_ROOT_PASSWORD=
MYSQL_BIND_HOST=127.0.0.1
MYSQL_HOST_PORT=3307
# 本地调试后端连接 MySQL(./dev.sh 使用;默认连接上面的宿主机端口)
DEV_DB_HOST=127.0.0.1
DEV_DB_PORT=3307
# 直接运行后端时使用;./dev.sh 会自动按 DEV_DB_* 和 MYSQL_* 生成这些变量
# DB_HOST=127.0.0.1
# DB_PORT=3307
# DB_NAME=douyu_login
# DB_USER=douyu_login
# DB_PASSWORD=
# 数据库连接池配置(仅 MySQL 生效) # 数据库连接池配置(仅 MySQL 生效)
DB_POOL_SIZE=20 DB_POOL_SIZE=20
+93 -6
View File
@@ -19,18 +19,43 @@ BACKEND_PORT="${BACKEND_PORT:-8800}"
FRONTEND_HOST="${FRONTEND_HOST:-0.0.0.0}" FRONTEND_HOST="${FRONTEND_HOST:-0.0.0.0}"
FRONTEND_PORT="${FRONTEND_PORT:-5174}" FRONTEND_PORT="${FRONTEND_PORT:-5174}"
LOG_LEVEL="${LOG_LEVEL:-DEBUG}" LOG_LEVEL="${LOG_LEVEL:-DEBUG}"
MYSQL_IMAGE="${MYSQL_IMAGE:-mysql:8.4}"
MYSQL_BIND_HOST="${MYSQL_BIND_HOST:-127.0.0.1}"
MYSQL_HOST_PORT="${MYSQL_HOST_PORT:-3307}"
MYSQL_DATABASE="${MYSQL_DATABASE:-douyu_login}"
MYSQL_USER="${MYSQL_USER:-douyu_login}"
DEV_DB_HOST="${DEV_DB_HOST:-127.0.0.1}"
DEV_DB_PORT="${DEV_DB_PORT:-$MYSQL_HOST_PORT}"
DB_HOST="$DEV_DB_HOST"
DB_PORT="$DEV_DB_PORT"
DB_NAME="${DB_NAME:-$MYSQL_DATABASE}"
DB_USER="${DB_USER:-$MYSQL_USER}"
DB_PASSWORD="${DB_PASSWORD:-${MYSQL_PASSWORD:-}}"
DB_POOL_SIZE="${DB_POOL_SIZE:-20}"
DB_MAX_OVERFLOW="${DB_MAX_OVERFLOW:-20}"
DB_POOL_TIMEOUT="${DB_POOL_TIMEOUT:-30}"
DB_POOL_RECYCLE="${DB_POOL_RECYCLE:-1800}"
BACKEND_PID="" BACKEND_PID=""
FRONTEND_PID="" FRONTEND_PID=""
stop_tree() {
local pid="$1"
local children
if [ -z "$pid" ] || ! kill -0 "$pid" 2>/dev/null; then
return
fi
children="$(pgrep -P "$pid" 2>/dev/null || true)"
for child in $children; do
stop_tree "$child"
done
kill "$pid" 2>/dev/null || true
}
cleanup() { cleanup() {
trap - EXIT INT TERM trap - EXIT INT TERM
if [ -n "$FRONTEND_PID" ] && kill -0 "$FRONTEND_PID" 2>/dev/null; then stop_tree "$FRONTEND_PID"
kill "$FRONTEND_PID" 2>/dev/null || true stop_tree "$BACKEND_PID"
fi
if [ -n "$BACKEND_PID" ] && kill -0 "$BACKEND_PID" 2>/dev/null; then
kill "$BACKEND_PID" 2>/dev/null || true
fi
} }
require_cmd() { require_cmd() {
@@ -42,9 +67,61 @@ require_cmd() {
require_cmd uv require_cmd uv
require_cmd npm require_cmd npm
require_cmd docker
detect_compose() {
if docker compose version >/dev/null 2>&1; then
echo "docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
echo "docker-compose"
else
echo ""
fi
}
if [ -n "${DATABASE_URL:-}" ] && [[ "$DATABASE_URL" != mysql+* ]]; then
echo "dev.sh 只支持 MySQL,请移除 SQLite DATABASE_URL: $DATABASE_URL"
exit 1
fi
if [ -z "${MYSQL_PASSWORD:-}" ] || [ -z "${MYSQL_ROOT_PASSWORD:-}" ]; then
echo "请先在 .env 中设置 MYSQL_PASSWORD 和 MYSQL_ROOT_PASSWORD"
exit 1
fi
if [ -z "$DB_PASSWORD" ]; then
echo "请先在 .env 中设置 DB_PASSWORD 或 MYSQL_PASSWORD"
exit 1
fi
COMPOSE=$(detect_compose)
if [ -z "$COMPOSE" ]; then
echo "缺少 docker compose"
exit 1
fi
mkdir -p data logs mkdir -p data logs
echo "正在启动本地 MySQL..."
MYSQL_IMAGE="$MYSQL_IMAGE" \
MYSQL_BIND_HOST="$MYSQL_BIND_HOST" \
MYSQL_HOST_PORT="$MYSQL_HOST_PORT" \
$COMPOSE up -d mysql
echo "等待 MySQL 就绪..."
for i in $(seq 1 30); do
if $COMPOSE exec -T mysql sh -c 'mysqladmin ping -h localhost -uroot -p"$MYSQL_ROOT_PASSWORD" --silent' >/dev/null 2>&1; then
echo "MySQL 已就绪"
break
fi
if [ "$i" = "30" ]; then
echo "MySQL 启动超时,查看日志:"
$COMPOSE logs --tail 50 mysql
exit 1
fi
sleep 2
done
echo "" echo ""
echo "==============================" echo "=============================="
echo " 本地调试模式" echo " 本地调试模式"
@@ -52,12 +129,22 @@ echo "=============================="
echo " 后端: http://${BACKEND_HOST}:${BACKEND_PORT}" echo " 后端: http://${BACKEND_HOST}:${BACKEND_PORT}"
echo " 前端: http://localhost:${FRONTEND_PORT}" echo " 前端: http://localhost:${FRONTEND_PORT}"
echo " API 代理: http://127.0.0.1:${BACKEND_PORT}" echo " API 代理: http://127.0.0.1:${BACKEND_PORT}"
echo " MySQL: ${DB_HOST}:${DB_PORT}/${DB_NAME}"
echo " 退出: Ctrl+C" echo " 退出: Ctrl+C"
echo "==============================" echo "=============================="
echo "" echo ""
trap cleanup EXIT INT TERM trap cleanup EXIT INT TERM
DB_HOST="$DB_HOST" \
DB_PORT="$DB_PORT" \
DB_NAME="$DB_NAME" \
DB_USER="$DB_USER" \
DB_PASSWORD="$DB_PASSWORD" \
DB_POOL_SIZE="$DB_POOL_SIZE" \
DB_MAX_OVERFLOW="$DB_MAX_OVERFLOW" \
DB_POOL_TIMEOUT="$DB_POOL_TIMEOUT" \
DB_POOL_RECYCLE="$DB_POOL_RECYCLE" \
LOG_LEVEL="$LOG_LEVEL" \ LOG_LEVEL="$LOG_LEVEL" \
uv run uvicorn web.backend.main:app \ uv run uvicorn web.backend.main:app \
--host "$BACKEND_HOST" \ --host "$BACKEND_HOST" \
+4 -1
View File
@@ -56,9 +56,12 @@ services:
retries: 3 retries: 3
mysql: mysql:
image: docker.m.daocloud.io/library/mysql:8.4 image: ${MYSQL_IMAGE:-docker.m.daocloud.io/library/mysql:8.4}
container_name: douyu-login-db container_name: douyu-login-db
restart: unless-stopped restart: unless-stopped
ports:
# 仅绑定宿主机本地地址,供 ./dev.sh 的本地后端连接,不对外网开放。
- "${MYSQL_BIND_HOST:-127.0.0.1}:${MYSQL_HOST_PORT:-3307}:3306"
environment: environment:
- TZ=Asia/Shanghai - TZ=Asia/Shanghai
- MYSQL_DATABASE=${MYSQL_DATABASE:-douyu_login} - MYSQL_DATABASE=${MYSQL_DATABASE:-douyu_login}
+4 -3
View File
@@ -8,8 +8,6 @@ from sqlalchemy import create_engine, event
from sqlalchemy.orm import sessionmaker, declarative_base from sqlalchemy.orm import sessionmaker, declarative_base
PROJECT_ROOT = Path(__file__).resolve().parents[2] PROJECT_ROOT = Path(__file__).resolve().parents[2]
DB_PATH = PROJECT_ROOT / "data" / "web.db"
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
def _env_int(name: str, default: int) -> int: def _env_int(name: str, default: int) -> int:
@@ -40,7 +38,10 @@ def _get_database_url() -> str:
f"@{db_host}:{db_port}/{db_name}?charset=utf8mb4" f"@{db_host}:{db_port}/{db_name}?charset=utf8mb4"
) )
return f"sqlite:///{DB_PATH}" raise RuntimeError(
"未配置数据库连接。请设置 DATABASE_URL=mysql+pymysql://..."
"或设置 DB_HOST、DB_NAME、DB_USER、DB_PASSWORD"
)
DATABASE_URL = _get_database_url() DATABASE_URL = _get_database_url()