# 数据库连接配置

> **文档版本：** 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<number> {
    const result = await prisma.$queryRaw<Array<{ count: bigint }>>`
      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  
**维护者：** 架构团队










