Files
happy-life-star/backend/数据库无外键设计说明.md
T

182 lines
5.4 KiB
Markdown

# 数据库无外键设计说明
## 📋 设计原则
### 🚫 不使用外键约束
本项目采用无外键约束的数据库设计,通过应用层代码维护数据关联关系。
## 🎯 设计理由
### 1. 性能优化
- **减少约束检查**: 数据库不需要在每次插入/更新时检查外键约束
- **提高并发性**: 避免外键锁定导致的并发问题
- **加快批量操作**: 大批量数据导入时无需考虑外键顺序
### 2. 开发灵活性
- **表结构调整**: 修改表结构时不需要先删除外键约束
- **数据迁移**: 数据迁移和同步更加简单
- **测试便利**: 测试数据准备更加灵活
### 3. 分布式友好
- **微服务架构**: 不同微服务可以独立管理自己的数据表
- **数据分片**: 便于后期进行数据库分片和分布式部署
- **跨库关联**: 支持跨数据库的数据关联
### 4. 维护简化
- **避免级联问题**: 不会因为外键级联操作导致意外的数据删除
- **减少死锁**: 降低因外键约束导致的数据库死锁概率
- **简化备份恢复**: 数据备份和恢复时无需考虑外键依赖顺序
## 🔗 关联关系维护
### 代码层面维护
通过业务代码确保数据一致性:
```java
// 示例:创建对话时关联用户
@Service
public class ConversationService {
@Autowired
private UserService userService;
@Autowired
private ConversationMapper conversationMapper;
public Conversation createConversation(String userId, String title) {
// 1. 验证用户是否存在
User user = userService.getById(userId);
if (user == null) {
throw new BusinessException("用户不存在");
}
// 2. 创建对话
Conversation conversation = new Conversation();
conversation.setUserId(userId); // 通过ID关联,不使用外键
conversation.setTitle(title);
conversationMapper.insert(conversation);
return conversation;
}
}
```
### 数据一致性保证
1. **业务层验证**: 在业务逻辑中验证关联数据的存在性
2. **事务管理**: 使用数据库事务确保操作的原子性
3. **定期检查**: 定期运行数据一致性检查脚本
## 📊 表关联关系
### 主要关联关系
```
user (用户表)
├── conversation.user_id → user.id
├── emotion_record.user_id → user.id
├── community_post.user_id → user.id
└── user_stats.user_id → user.id
conversation (对话表)
├── message.conversation_id → conversation.id
└── coze_api_call.conversation_id → conversation.id
message (消息表)
├── emotion_analysis.message_id → message.id
└── coze_api_call.message_id → message.id
community_post (社区帖子表)
└── comment.post_id → community_post.id
growth_topic (成长课题表)
├── topic_interaction.topic_id → growth_topic.id
└── reward.topic_id → growth_topic.id
achievement (成就表)
└── reward.achievement_id → achievement.id
```
### 关联字段命名规范
- **外部ID字段**: 统一使用 `{table_name}_id` 格式
- **主键字段**: 统一使用 `id`
- **数据类型**: 统一使用 `VARCHAR(36)` 雪花算法ID
## 🛡️ 数据完整性保证
### 1. 应用层验证
```java
// 删除用户前检查关联数据
public void deleteUser(String userId) {
// 检查是否有关联的对话
if (conversationService.countByUserId(userId) > 0) {
throw new BusinessException("用户存在关联对话,无法删除");
}
// 检查是否有关联的情绪记录
if (emotionRecordService.countByUserId(userId) > 0) {
throw new BusinessException("用户存在情绪记录,无法删除");
}
userService.deleteById(userId);
}
```
### 2. 定期数据检查
```sql
-- 检查孤立的对话记录(用户不存在)
SELECT c.id, c.user_id
FROM conversation c
LEFT JOIN user u ON c.user_id = u.id
WHERE u.id IS NULL AND c.is_deleted = 0;
-- 检查孤立的消息记录(对话不存在)
SELECT m.id, m.conversation_id
FROM message m
LEFT JOIN conversation c ON m.conversation_id = c.id
WHERE c.id IS NULL AND m.is_deleted = 0;
```
### 3. 软删除策略
- 使用 `is_deleted` 字段标记删除状态
- 保留历史数据,避免硬删除导致的关联数据问题
- 定期清理真正需要删除的数据
## 🔧 最佳实践
### 1. 服务层设计
- **单一职责**: 每个服务只管理自己的数据表
- **接口调用**: 跨表查询通过服务接口调用
- **缓存策略**: 合理使用缓存减少跨表查询
### 2. 查询优化
- **索引设计**: 为关联字段创建合适的索引
- **批量查询**: 使用 IN 查询减少数据库访问次数
- **分页处理**: 大数据量查询时合理分页
### 3. 数据迁移
- **脚本化**: 数据迁移操作脚本化,可重复执行
- **验证机制**: 迁移后验证数据完整性
- **回滚方案**: 准备数据回滚方案
## ⚠️ 注意事项
### 1. 开发规范
- 严格按照关联关系进行数据操作
- 删除数据前必须检查关联关系
- 使用事务确保数据一致性
### 2. 监控告警
- 监控孤立数据的产生
- 定期检查数据一致性
- 异常情况及时告警
### 3. 文档维护
- 及时更新关联关系文档
- 记录数据操作规范
- 维护数据字典
---
**设计原则**: 简单、高效、可维护
**实施策略**: 代码约束 + 定期检查
**适用场景**: 微服务架构 + 高并发系统