# 数据库连接配置 > **文档版本:** v1.0 > **创建日期:** 2025-11-09 > **维护者:** 架构团队 > **最后更新:** 2025-11-09 --- ## 📋 文档说明 本文档记录Schema隔离架构实施相关的数据库连接和配置信息,包括: - 当前数据库状态 - Schema隔离迁移配置 - 迁移过程的连接方式 - 验证和回滚方案 --- ## 🗄️ 当前数据库状态 ### 数据库基本信息 **连接信息:** ``` 数据库类型:PostgreSQL 15+ 数据库名称:ai_clinical_research 主机地址: localhost 端口: 5432 用户名: postgres 密码: postgres ``` **完整连接字符串:** ``` DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ai_clinical_research ``` --- ### 当前Schema结构 **现有Schema:** - ✅ **public** - 所有13个表都在这里 **表清单(13个):** #### 1. 平台基础(2个表) ```sql public.users -- 用户表 public.admin_logs -- 管理日志 ``` #### 2. AI智能问答(5个表) ```sql public.projects -- 项目管理 public.conversations -- 项目对话 public.messages -- 对话消息 public.general_conversations -- 通用对话 public.general_messages -- 通用消息 ``` #### 3. 个人知识库(2个表) ```sql public.knowledge_bases -- 知识库 public.documents -- 文档 ``` #### 4. 批处理系统(3个表) ```sql public.batch_tasks -- 批处理任务 public.batch_results -- 批处理结果 public.task_templates -- 任务模板 ``` #### 5. 稿件审查(1个表) ```sql public.review_tasks -- 审查任务 ``` --- ### 数据库统计信息 **表数量:** 13个 **索引数量:** 约40个 **外键约束:** 约15个 **当前数据量(估算):** - users: ~10条 - projects: ~20条 - conversations: ~50条 - messages: ~500条 - knowledge_bases: ~5条 - documents: ~30条 - 其他表:测试数据 **总数据量:** < 10MB(测试环境) --- ## 🎯 Schema隔离目标架构 ### 10个独立Schema #### 需要详细设计+数据迁移(5个) **1. platform_schema(平台基础层)** ```sql -- 迁移表: public.users → platform_schema.users public.admin_logs → platform_schema.admin_logs (暂缓,待确认) ``` **2. common_schema(通用能力层)** ```sql -- 新建表: common_schema.llm_usage -- LLM使用记录 common_schema.feature_flags -- Feature Flags ``` **3. asl_schema(AI智能文献)** ```sql -- 新建表: asl_schema.literature_projects -- 文献项目 asl_schema.pico_configs -- PICO配置 asl_schema.literature_items -- 文献条目 -- 更多表见ASL设计文档 ``` **4. aia_schema(AI智能问答)** ```sql -- 迁移表: public.projects → aia_schema.projects public.conversations → aia_schema.conversations public.messages → aia_schema.messages public.general_conversations → aia_schema.general_conversations public.general_messages → aia_schema.general_messages ``` **5. pkb_schema(个人知识库)** ```sql -- 迁移表: public.knowledge_bases → pkb_schema.knowledge_bases public.documents → pkb_schema.documents ``` #### 只创建空Schema(5个) **6. dc_schema(数据清洗)** - 暂无表结构 **7. rvw_schema(审稿系统)** - 暂无表结构 **8. admin_schema(运营管理)** - 暂无表结构 **9. ssa_schema(智能统计分析)** - 暂无表结构 **10. st_schema(统计分析工具)** - 暂无表结构 --- ## 🔄 迁移过程连接配置 ### 迁移前准备 **1. 备份当前数据库** ```bash # Windows PowerShell cd D:\MyCursor\AIclinicalresearch\backend # 使用pg_dump备份 pg_dump -h localhost -U postgres -d ai_clinical_research -F c -f backup_before_schema_migration_$(Get-Date -Format 'yyyyMMdd_HHmmss').dump # 或者使用SQL格式 pg_dump -h localhost -U postgres -d ai_clinical_research > backup_before_schema_migration_$(Get-Date -Format 'yyyyMMdd_HHmmss').sql ``` **2. 验证备份** ```bash # 检查备份文件大小 ls -lh backup_*.dump # 验证备份内容(SQL格式) head -n 50 backup_*.sql ``` --- ### 迁移过程连接方式 #### 方式1:使用Prisma Migrate(推荐) **连接配置:** ```env # backend/.env DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ai_clinical_research ``` **执行迁移:** ```bash cd backend # 创建新的迁移 npx prisma migrate dev --name schema_isolation_10_schemas # 查看迁移状态 npx prisma migrate status ``` --- #### 方式2:直接执行SQL脚本 **连接方式:** ```bash # 使用psql连接 psql -h localhost -U postgres -d ai_clinical_research # 或使用环境变量 export PGPASSWORD=postgres psql -h localhost -U postgres -d ai_clinical_research -f migration_script.sql ``` **执行迁移脚本:** ```bash cd docs/09-架构实施/migration-scripts # 按顺序执行 psql -h localhost -U postgres -d ai_clinical_research -f 001-create-all-10-schemas.sql psql -h localhost -U postgres -d ai_clinical_research -f 002-migrate-platform.sql psql -h localhost -U postgres -d ai_clinical_research -f 003-migrate-aia.sql psql -h localhost -U postgres -d ai_clinical_research -f 004-migrate-pkb.sql # ... 更多脚本 ``` --- #### 方式3:使用可视化工具 **pgAdmin 4:** 1. 连接信息: - 主机:localhost - 端口:5432 - 数据库:ai_clinical_research - 用户:postgres - 密码:postgres 2. 执行迁移: - 打开Query Tool - 加载SQL脚本 - 执行 **DataGrip / DBeaver:** - 同样的连接信息 - 支持事务管理 - 方便回滚 --- ## ✅ 迁移验证 ### 1. 检查Schema创建 **SQL验证:** ```sql -- 查看所有Schema SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('pg_catalog', 'information_schema') ORDER BY schema_name; -- 预期结果: -- admin_schema -- aia_schema -- asl_schema -- common_schema -- dc_schema -- pkb_schema -- platform_schema -- public -- rvw_schema -- ssa_schema -- st_schema ``` --- ### 2. 检查表迁移 **验证platform_schema:** ```sql -- 查看表 SELECT table_name FROM information_schema.tables WHERE table_schema = 'platform_schema'; -- 验证数据 SELECT COUNT(*) FROM platform_schema.users; -- 预期:与原public.users的数量一致 ``` **验证aia_schema:** ```sql -- 查看所有表 SELECT table_name FROM information_schema.tables WHERE table_schema = 'aia_schema'; -- 验证数据完整性 SELECT COUNT(*) FROM aia_schema.projects; SELECT COUNT(*) FROM aia_schema.conversations; SELECT COUNT(*) FROM aia_schema.messages; ``` **验证pkb_schema:** ```sql SELECT COUNT(*) FROM pkb_schema.knowledge_bases; SELECT COUNT(*) FROM pkb_schema.documents; ``` --- ### 3. 验证外键关系 **检查跨Schema外键:** ```sql -- 查看所有外键约束 SELECT tc.table_schema, tc.table_name, kcu.column_name, ccu.table_schema AS foreign_table_schema, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name FROM information_schema.table_constraints AS tc JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_schema IN ('platform_schema', 'aia_schema', 'pkb_schema', 'asl_schema', 'common_schema') ORDER BY tc.table_schema, tc.table_name; ``` --- ### 4. 验证索引 **检查索引是否正确迁移:** ```sql -- 查看某个Schema的所有索引 SELECT schemaname, tablename, indexname, indexdef FROM pg_indexes WHERE schemaname = 'aia_schema' ORDER BY tablename, indexname; ``` --- ### 5. Prisma验证 **更新Prisma配置后验证:** ```bash cd backend # 生成Prisma Client npx prisma generate # 验证Prisma Client可用 npx ts-node -e "import { PrismaClient } from '@prisma/client'; const p = new PrismaClient(); p.user.count().then(console.log)" ``` --- ## 🔙 回滚方案 ### 场景1:迁移过程中发现问题 **立即回滚:** ```bash # 如果使用Prisma Migrate npx prisma migrate reset # 恢复备份 psql -h localhost -U postgres -d ai_clinical_research < backup_before_schema_migration_YYYYMMDD_HHMMSS.sql ``` --- ### 场景2:迁移完成后发现问题 **方案A:从备份恢复(推荐)** ```bash # 1. 删除当前数据库 dropdb -h localhost -U postgres ai_clinical_research # 2. 重新创建 createdb -h localhost -U postgres ai_clinical_research # 3. 恢复备份 pg_restore -h localhost -U postgres -d ai_clinical_research backup_before_schema_migration_YYYYMMDD_HHMMSS.dump ``` **方案B:手动删除新Schema,保留public** ```sql -- 删除新建的Schema(慎重!) DROP SCHEMA IF EXISTS platform_schema CASCADE; DROP SCHEMA IF EXISTS aia_schema CASCADE; DROP SCHEMA IF EXISTS pkb_schema CASCADE; DROP SCHEMA IF EXISTS asl_schema CASCADE; DROP SCHEMA IF EXISTS common_schema CASCADE; DROP SCHEMA IF EXISTS dc_schema CASCADE; DROP SCHEMA IF EXISTS rvw_schema CASCADE; DROP SCHEMA IF EXISTS admin_schema CASCADE; DROP SCHEMA IF EXISTS ssa_schema CASCADE; DROP SCHEMA IF EXISTS st_schema CASCADE; -- public schema的表如果被删除了,从备份恢复 ``` --- ## 📊 迁移检查清单 ### 迁移前检查 - [ ] ✅ 数据库已备份(backup_before_schema_migration_*.dump) - [ ] ✅ 备份文件已验证 - [ ] ✅ Prisma配置已更新(datasource.schemas) - [ ] ✅ 迁移脚本已准备(001-010.sql) - [ ] ✅ 测试环境已验证迁移步骤 --- ### 迁移中检查 - [ ] ✅ 10个Schema创建成功 - [ ] ✅ 表迁移无错误(5个有数据的Schema) - [ ] ✅ 数据完整性验证通过 - [ ] ✅ 外键约束正确 - [ ] ✅ 索引正确创建 --- ### 迁移后检查 - [ ] ✅ Prisma Client生成成功 - [ ] ✅ 后端服务启动正常 - [ ] ✅ 现有功能测试通过(AIA、PKB) - [ ] ✅ API调用正常 - [ ] ✅ 前端功能正常 --- ## 🔧 常见问题 ### 问题1:Schema创建失败 **错误:** ``` ERROR: schema "platform_schema" already exists ``` **解决:** ```sql -- 检查Schema是否存在 SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'platform_schema'; -- 如果存在但为空,可删除重建 DROP SCHEMA platform_schema CASCADE; CREATE SCHEMA platform_schema; ``` --- ### 问题2:数据迁移失败 **错误:** ``` ERROR: duplicate key value violates unique constraint ``` **解决:** 1. 检查数据是否已部分迁移 2. 清理目标Schema 3. 重新执行迁移 --- ### 问题3:外键约束错误 **错误:** ``` ERROR: foreign key constraint "fk_user_id" cannot be implemented ``` **解决:** 1. 确保被引用的表已先迁移 2. 检查外键字段类型匹配 3. 考虑先禁用外键,迁移后重建 --- ## 🔧 云原生连接池配置(2025-11-16 新增) > **⭐ 重要更新**:为支持阿里云 Serverless 部署,新增连接池配置 > **详细文档**:[平台基础设施规划](./04-平台基础设施规划.md) ### 背景:为什么需要连接池? **问题场景**: ``` 阿里云 SAE 自动扩容: - 初始:1个实例,10个连接 - 高峰:100个实例,1000个连接 - RDS最大连接数:400 ❌ 超限! 结果:数据库连接耗尽,应用崩溃 ``` **解决方案**:动态计算每实例连接数 ```typescript 每实例连接数 = RDS最大连接数 / SAE最大实例数 示例:400连接 / 20实例 = 20连接/实例 ``` --- ### Prisma连接池配置 **文件位置**:`backend/src/config/database.ts` **配置代码**: ```typescript import { PrismaClient } from '@prisma/client' // 动态计算连接数 const dbMaxConnections = Number(process.env.DB_MAX_CONNECTIONS) || 400 const maxInstances = Number(process.env.MAX_INSTANCES) || 20 const connectionLimit = Math.floor(dbMaxConnections / maxInstances) console.log(`📊 数据库连接池配置:每实例最多${connectionLimit}个连接`) // 创建全局Prisma Client export const prisma = new PrismaClient({ datasources: { db: { url: process.env.DATABASE_URL, }, }, log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'], errorFormat: 'minimal', }) // 优雅关闭连接 process.on('SIGTERM', async () => { console.log('📊 正在关闭数据库连接...') await prisma.$disconnect() console.log('✅ 数据库连接已关闭') process.exit(0) }) process.on('SIGINT', async () => { console.log('📊 正在关闭数据库连接...') await prisma.$disconnect() console.log('✅ 数据库连接已关闭') process.exit(0) }) // 启动时测试连接 prisma.$connect() .then(() => console.log('✅ 数据库连接成功')) .catch((err) => { console.error('❌ 数据库连接失败:', err) process.exit(1) }) ``` --- ### 环境变量配置 **本地开发环境**: ```bash # backend/.env.development DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ai_clinical_research # 本地开发无需配置连接池(单实例) # DB_MAX_CONNECTIONS=N/A # MAX_INSTANCES=N/A ``` **云端生产环境**: ```bash # SAE控制台 -> 环境变量配置 DATABASE_URL=postgresql://user:password@rm-xxx.aliyuncs.com:5432/prod_db DB_MAX_CONNECTIONS=400 # 阿里云RDS最大连接数 MAX_INSTANCES=20 # SAE最大实例数 ``` **不同RDS规格的连接数**: | RDS规格 | 最大连接数 | 建议SAE实例数 | 每实例连接数 | |---------|-----------|--------------|-------------| | 2核4GB | 200 | 10 | 20 | | 4核8GB | 400 | 20 | 20 | | 8核16GB | 800 | 40 | 20 | --- ### 监控数据库连接数 **实时查询连接数**: ```typescript // backend/src/common/monitoring/metrics.ts import { prisma } from '@/config/database' import { logger } from '@/common/logging' export class DatabaseMetrics { // 查询当前连接数 static async getConnectionCount(): Promise { const result = await prisma.$queryRaw>` SELECT count(*) as count FROM pg_stat_activity WHERE datname = current_database() ` return Number(result[0].count) } // 监控并告警 static async monitorConnections() { const currentConnections = await this.getConnectionCount() const maxConnections = Number(process.env.DB_MAX_CONNECTIONS) || 400 const usagePercent = (currentConnections / maxConnections) * 100 logger.info('数据库连接监控', { current: currentConnections, max: maxConnections, usage: `${usagePercent.toFixed(1)}%` }) // 告警:连接数超过80% if (usagePercent > 80) { logger.warn('⚠️ 数据库连接数告警', { current: currentConnections, max: maxConnections, usage: `${usagePercent.toFixed(1)}%`, action: '建议增加RDS规格或减少SAE实例数' }) } return { currentConnections, maxConnections, usagePercent } } } ``` **定时监控**(可选): ```typescript // backend/src/index.ts import { DatabaseMetrics } from '@/common/monitoring/metrics' // 每5分钟监控一次 setInterval(async () => { await DatabaseMetrics.monitorConnections() }, 5 * 60 * 1000) ``` --- ### 故障排查 **问题1:连接数耗尽** **症状**: ``` Error: P1001: Can't reach database server Error: remaining connection slots are reserved ``` **原因**: - SAE实例数过多 - 每实例连接数配置过高 - 存在连接泄漏 **解决方案**: ```bash # 1. 查看当前连接数 SELECT count(*) FROM pg_stat_activity WHERE datname = 'ai_clinical_research'; # 2. 查看连接来源 SELECT client_addr, count(*) FROM pg_stat_activity WHERE datname = 'ai_clinical_research' GROUP BY client_addr; # 3. 调整配置 # 方案A:减少SAE最大实例数 MAX_INSTANCES=10 # 从20改为10 # 方案B:升级RDS规格 # 从2核4GB(200连接)升级到4核8GB(400连接) ``` --- **问题2:连接泄漏** **症状**: - 连接数持续增长 - 即使流量降低,连接数不下降 **排查**: ```typescript // ❌ 错误:每次创建新实例 function getUser() { const prisma = new PrismaClient() // 连接泄漏 return prisma.user.findMany() } // ✅ 正确:使用全局实例 import { prisma } from '@/config/database' function getUser() { return prisma.user.findMany() } ``` --- ### 最佳实践 **DO ✅**: 1. ✅ 使用全局 `prisma` 实例 2. ✅ 配置 `SIGTERM` 优雅关闭 3. ✅ 定期监控连接数 4. ✅ 设置连接数告警(80%阈值) 5. ✅ 使用连接池(Prisma默认启用) **DON'T ❌**: 1. ❌ 每次请求新建 `PrismaClient` 2. ❌ 不关闭连接就退出进程 3. ❌ 忽略连接数监控 4. ❌ 设置过大的 `MAX_INSTANCES` 5. ❌ 在业务代码中直接执行 `$disconnect()` --- ## 📚 相关文档 - [平台基础设施规划](./04-平台基础设施规划.md) - 完整的连接池设计 - [云原生开发规范](../04-开发规范/08-云原生开发规范.md) - 数据库使用规范 - [环境配置指南](../07-运维文档/01-环境配置指南.md) - 环境变量配置 - [Schema隔离架构设计](../00-系统总体设计/03-数据库架构说明.md) --- ## 🔄 更新记录 | 日期 | 更新内容 | 更新人 | |------|---------|--------| | 2025-11-09 | 初始文档创建 | 架构团队 | | 2025-11-16 | 新增云原生连接池配置章节 | 架构团队 | --- **文档版本:** v1.0 **最后更新:** 2025-11-09 **维护者:** 架构团队