# 数据库无外键设计说明 ## 📋 设计原则 ### 🚫 不使用外键约束 本项目采用无外键约束的数据库设计,通过应用层代码维护数据关联关系。 ## 🎯 设计理由 ### 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. 文档维护 - 及时更新关联关系文档 - 记录数据操作规范 - 维护数据字典 --- **设计原则**: 简单、高效、可维护 **实施策略**: 代码约束 + 定期检查 **适用场景**: 微服务架构 + 高并发系统