From 3f3821581c560430efe90a35f287dd07eec30e20 Mon Sep 17 00:00:00 2001 From: Xiaoxia AI Date: Wed, 17 Jun 2026 08:25:20 +0800 Subject: [PATCH] feat(config): add database switch between InMemory and PostgreSQL - Add USE_IN_MEMORY_DB config flag - Auto-select repository implementation based on config - InMemory: for development and testing (no setup needed) - PostgreSQL: for production (persistent data) - Update DependencyContainer to support both - Add documentation for switching databases - Update .env.example with new config Phase 4 Task 36/68 completed --- .env.example | 6 + apps/api/app/config.py | 1 + apps/api/app/dependencies.py | 24 +++- docs/DATABASE-SWITCH.md | 216 +++++++++++++++++++++++++++++++++++ 4 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 docs/DATABASE-SWITCH.md diff --git a/.env.example b/.env.example index c564a7410..bc7a27839 100644 --- a/.env.example +++ b/.env.example @@ -7,6 +7,12 @@ BASE_URL=http://localhost:3000 # ==================== 数据库配置 ==================== DATABASE_URL=postgresql://xiaoxia_user:your_password@localhost:5432/xiaoxia_saas +# 开发环境:使用内存数据库(不需要 PostgreSQL) +USE_IN_MEMORY_DB=true + +# 生产环境:使用 PostgreSQL +# USE_IN_MEMORY_DB=false + # ==================== Redis 配置 ==================== REDIS_URL=redis://localhost:6379/0 diff --git a/apps/api/app/config.py b/apps/api/app/config.py index 481cae8d9..516cd011e 100644 --- a/apps/api/app/config.py +++ b/apps/api/app/config.py @@ -16,6 +16,7 @@ class Settings(BaseSettings): # 数据库配置 DATABASE_URL: str = "postgresql://xiaoxia:password@localhost:5432/xiaoxia_saas" + USE_IN_MEMORY_DB: bool = False # True = 使用内存数据库,False = 使用 PostgreSQL # Redis 配置 REDIS_URL: str = "redis://localhost:6379/0" diff --git a/apps/api/app/dependencies.py b/apps/api/app/dependencies.py index 4b2da51dc..4c86d76c3 100644 --- a/apps/api/app/dependencies.py +++ b/apps/api/app/dependencies.py @@ -55,19 +55,37 @@ class DependencyContainer: @property def user_repository(self): if self._user_repository is None: - self._user_repository = InMemoryUserRepository() + from apps.api.app.config import settings + if settings.USE_IN_MEMORY_DB: + from packages.adapters.in_memory.user_repository import InMemoryUserRepository + self._user_repository = InMemoryUserRepository() + else: + from packages.adapters.postgres.user_repository import PostgresUserRepository + self._user_repository = PostgresUserRepository(settings.DATABASE_URL) return self._user_repository @property def workspace_repository(self): if self._workspace_repository is None: - self._workspace_repository = InMemoryWorkspaceRepository() + from apps.api.app.config import settings + if settings.USE_IN_MEMORY_DB: + from packages.adapters.in_memory.workspace_repository import InMemoryWorkspaceRepository + self._workspace_repository = InMemoryWorkspaceRepository() + else: + from packages.adapters.postgres.workspace_repository import PostgresWorkspaceRepository + self._workspace_repository = PostgresWorkspaceRepository(settings.DATABASE_URL) return self._workspace_repository @property def workspace_member_repository(self): if self._workspace_member_repository is None: - self._workspace_member_repository = InMemoryWorkspaceMemberRepository() + from apps.api.app.config import settings + if settings.USE_IN_MEMORY_DB: + from packages.adapters.in_memory.workspace_member_repository import InMemoryWorkspaceMemberRepository + self._workspace_member_repository = InMemoryWorkspaceMemberRepository() + else: + from packages.adapters.postgres.workspace_member_repository import PostgresWorkspaceMemberRepository + self._workspace_member_repository = PostgresWorkspaceMemberRepository(settings.DATABASE_URL) return self._workspace_member_repository @property diff --git a/docs/DATABASE-SWITCH.md b/docs/DATABASE-SWITCH.md new file mode 100644 index 000000000..7bebe45e9 --- /dev/null +++ b/docs/DATABASE-SWITCH.md @@ -0,0 +1,216 @@ +# 数据库切换指南 + +## 📚 概述 + +小虾 SaaS 支持两种数据存储方式: +1. **InMemory(内存数据库)** - 开发和测试环境 +2. **PostgreSQL** - 生产环境 + +通过环境变量 `USE_IN_MEMORY_DB` 控制。 + +--- + +## 🔄 快速切换 + +### 方式 1: 环境变量 + +在 `.env` 文件中设置: + +```env +# 使用内存数据库(开发/测试) +USE_IN_MEMORY_DB=true + +# 使用 PostgreSQL(生产) +USE_IN_MEMORY_DB=false +DATABASE_URL=postgresql://user:pass@localhost:5432/xiaoxia_saas +``` + +### 方式 2: 启动时指定 + +```bash +# 使用内存数据库 +USE_IN_MEMORY_DB=true uvicorn apps.api.main:app --reload + +# 使用 PostgreSQL +USE_IN_MEMORY_DB=false uvicorn apps.api.main:app --reload +``` + +--- + +## 💡 InMemory 数据库 + +**特点:** +- ✅ 无需安装 PostgreSQL +- ✅ 无需数据库迁移 +- ✅ 快速启动 +- ✅ 适合开发和测试 +- ❌ 重启后数据丢失 +- ❌ 不适合生产环境 + +**使用场景:** +- 本地开发 +- 单元测试 +- 集成测试 +- 快速原型验证 + +**启动:** +```bash +# 设置环境变量 +export USE_IN_MEMORY_DB=true + +# 启动服务 +uvicorn apps.api.main:app --reload +``` + +--- + +## 🗄️ PostgreSQL 数据库 + +**特点:** +- ✅ 数据持久化 +- ✅ 支持事务 +- ✅ 生产就绪 +- ✅ 支持并发 +- ❌ 需要安装 PostgreSQL +- ❌ 需要运行数据库迁移 + +**使用场景:** +- 生产环境 +- 预发布环境 +- 需要数据持久化的场景 + +**设置步骤:** + +1. **安装 PostgreSQL** + ```bash + # Ubuntu + sudo apt-get install postgresql + + # macOS + brew install postgresql + ``` + +2. **创建数据库** + ```bash + sudo -u postgres psql + CREATE DATABASE xiaoxia_saas; + CREATE USER xiaoxia_user WITH PASSWORD 'your_password'; + GRANT ALL PRIVILEGES ON DATABASE xiaoxia_saas TO xiaoxia_user; + \q + ``` + +3. **运行迁移** + ```bash + psql postgresql://xiaoxia_user:password@localhost:5432/xiaoxia_saas \ + -f migrations/001_initial_schema.sql + ``` + +4. **配置环境变量** + ```env + USE_IN_MEMORY_DB=false + DATABASE_URL=postgresql://xiaoxia_user:password@localhost:5432/xiaoxia_saas + ``` + +5. **启动服务** + ```bash + uvicorn apps.api.main:app --reload + ``` + +--- + +## 🐳 Docker 环境 + +### docker-compose(自动配置 PostgreSQL) + +```bash +# 自动启动 PostgreSQL 和应用 +docker-compose up -d + +# 查看日志 +docker-compose logs -f api +``` + +`docker-compose.yml` 默认使用 PostgreSQL。 + +--- + +## 🧪 测试环境 + +### 单元测试(推荐 InMemory) + +```python +# tests/conftest.py +import os +os.environ['USE_IN_MEMORY_DB'] = 'true' +``` + +### 集成测试(可选 PostgreSQL) + +```bash +# 使用 PostgreSQL 进行集成测试 +USE_IN_MEMORY_DB=false pytest tests/integration -v +``` + +--- + +## 🔧 实现原理 + +依赖注入容器根据配置自动选择: + +```python +# apps/api/app/dependencies.py +@property +def user_repository(self): + if settings.USE_IN_MEMORY_DB: + return InMemoryUserRepository() + else: + return PostgresUserRepository(settings.DATABASE_URL) +``` + +**优点:** +- 业务逻辑无需改动 +- 切换透明 +- 测试隔离 + +--- + +## ⚠️ 注意事项 + +1. **数据不兼容** + - InMemory 和 PostgreSQL 之间无法直接迁移数据 + - 切换前请备份重要数据 + +2. **性能差异** + - InMemory 更快(无 I/O) + - PostgreSQL 支持更大数据量 + +3. **并发支持** + - InMemory 不支持多进程 + - PostgreSQL 支持多进程和集群 + +4. **环境一致性** + - 开发环境建议使用 InMemory + - 生产环境必须使用 PostgreSQL + +--- + +## 🚀 最佳实践 + +1. **开发流程** + ``` + 开发(InMemory) → 测试(InMemory) → 预发布(PostgreSQL) → 生产(PostgreSQL) + ``` + +2. **配置管理** + - 使用 `.env` 文件管理配置 + - 不要提交 `.env` 到版本控制 + - 使用 `.env.example` 作为模板 + +3. **数据库迁移** + - 所有 schema 变更都要有迁移脚本 + - 迁移脚本要幂等(可多次执行) + - 测试迁移脚本后再应用到生产 + +--- + +**最后更新:** 2026-06-17