Files
012-kaopeilian/知识库/问题修复/资料上传数据库持久化问题修复报告.md
111 998211c483 feat: 初始化考培练系统项目
- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
2026-01-24 19:33:28 +08:00

7.9 KiB
Raw Permalink Blame History

资料上传数据库持久化问题修复报告

修复日期2025-10-17
问题来源:用户反馈
严重级别⚠️ 高(数据丢失)
影响范围:课程资料上传功能


📋 问题描述

用户反馈

在课程编辑页面 https://aiedu.ireborn.com.cn/manager/edit-course/1 上传资料后:

  • 资料上传成功(文件被保存)
  • 前端显示"上传成功"消息
  • 刷新页面后,资料记录消失
  • 数据库中没有资料记录

复现步骤

  1. 登录管理员账号
  2. 进入课程编辑页面
  3. 点击"上传资料"按钮
  4. 选择文件并上传
  5. 看到"上传成功"提示
  6. 刷新页面
  7. 发现资料列表为空

🔍 问题分析

根本原因

数据库事务未提交后端service层只执行了 db.flush() 但没有 db.commit()

技术细节

1. 错误代码位置

文件:/root/aiedu/kaopeilian-backend/app/services/course_service.py
函数:add_course_material (第313-361行)

# ❌ 第346-349行的错误代码
material = CourseMaterial(**material_data)
db.add(material)
await db.flush()  # ⚠️ 只刷新到数据库,未提交事务
await db.refresh(material)

2. 问题分析

db.flush() vs db.commit() 的区别

操作 作用 数据持久化
db.flush() 将待处理的更改同步到数据库生成ID 否,事务未提交
db.commit() 提交事务,将更改永久保存到数据库 是,数据已持久化

为什么前端能看到成功响应?

  1. service层执行 db.flush()CourseMaterial对象获得了自增ID
  2. API函数正常返回包含ID的资料对象
  3. 前端收到成功响应code=200, data={id: xxx, ...}
  4. 前端显示"上传成功"消息

为什么数据库没有记录?

  1. db.flush() 只是将更改发送到数据库,但事务未提交
  2. FastAPI的 get_db() 依赖注入在请求结束时会自动提交
  3. 但在某些情况下(如后台任务、异常处理等),可能导致时序问题
  4. 最终事务回滚,数据丢失

3. 数据流程

用户上传文件
    ↓
前端调用 POST /api/v1/upload/course/{id}/materials
    ↓
后端保存物理文件到 /static/uploads/courses/{id}/
    ↓
返回 file_url, file_type, file_size
    ↓
前端调用 POST /api/v1/courses/{id}/materials
    ↓
后端创建 CourseMaterial 对象
    ↓
db.add(material)
    ↓
await db.flush()  ← ⚠️ 问题点只flush未commit
    ↓
返回成功响应包含material.id
    ↓
⚠️ 事务结束时,数据被回滚
    ↓
❌ 数据库中没有记录

🔧 修复方案

代码修改

文件/root/aiedu/kaopeilian-backend/app/services/course_service.py
位置第348行

# ✅ 修复后的代码
material = CourseMaterial(**material_data)
db.add(material)
await db.commit()  # ✅ 提交事务,确保数据持久化
await db.refresh(material)

修改说明

  • await db.flush() 改为 await db.commit()
  • 确保数据在返回前已经提交到数据库
  • 保留 await db.refresh(material) 以获取数据库生成的字段如created_at

验证测试

1. 服务重启

docker restart kaopeilian-backend-dev

2. 功能测试

测试步骤

  1. 访问 https://aiedu.ireborn.com.cn/manager/edit-course/1
  2. 点击"上传资料"按钮
  3. 选择测试文件如PDF文档
  4. 点击"确认上传"
  5. 等待上传完成提示
  6. 刷新页面
  7. 验证资料列表是否显示上传的文件

预期结果

  • 文件上传成功
  • 前端显示"文件上传成功"消息
  • 刷新页面后,资料列表显示该文件
  • 数据库中有对应记录

3. 数据库验证

-- 查询最新上传的资料
SELECT 
    id, 
    course_id, 
    name, 
    file_type, 
    file_size,
    created_at,
    is_deleted
FROM course_materials 
WHERE course_id = 1 
  AND is_deleted = 0 
ORDER BY id DESC 
LIMIT 5;

预期结果:能看到刚刚上传的资料记录


📊 影响范围

直接影响

  • 课程资料上传功能
  • 资料管理功能
  • 知识点管理(依赖资料)

潜在影响

  • 其他service函数可能存在类似问题
  • 建议全局搜索 db.flush() 并检查是否有相应的 commit()

检查结果

# 搜索所有使用 db.flush() 的地方
grep -rn "await db.flush()" /root/aiedu/kaopeilian-backend/app/services/

发现的其他位置:

  • task_service.py: 正确使用flush后有commit
  • create_team_data.py: 脚本文件在最后有统一commit

📚 经验总结

1. 事务管理的重要性

  • flush() 用于获取自增ID不保证数据持久化
  • commit() 才能真正保存数据到数据库
  • 在service层进行数据修改时必须确保commit

2. "假成功"问题的排查思路

  1. 检查物理文件是否存在(确认上传成功)
  2. 检查数据库是否有记录(确认落库成功)
  3. 检查后端日志是否有异常
  4. 检查service层是否正确提交事务
  5. 使用浏览器开发者工具查看API响应

3. FastAPI事务管理机制

  • get_db() 依赖注入会在请求结束时自动commit
  • 但service层的显式commit更安全、更清晰
  • 不要依赖框架的自动提交机制

4. 代码审查要点

  • 检查所有 db.add() 后是否有相应的 db.commit()
  • 检查 db.flush() 的使用场景是否合理
  • 确保所有数据修改操作都有明确的事务提交
  • 验证异常处理中的事务回滚逻辑

🎯 预防措施

1. 建立Service层事务规范

# 标准模式:添加 → 提交 → 刷新
db.add(obj)
await db.commit()
await db.refresh(obj)
return obj

2. 代码审查检查清单

  • 所有 db.add() 是否有对应的 db.commit()
  • db.flush() 的使用是否必要通常只在需要ID时使用
  • 批量操作是否在循环外统一提交
  • 是否有适当的异常处理和事务回滚

3. 自动化测试

# 测试数据持久化
async def test_add_material_persists():
    """测试资料创建后数据确实保存到数据库"""
    material = await course_service.add_course_material(...)
    
    # 在新会话中查询,验证数据已持久化
    async with AsyncSessionLocal() as new_db:
        result = await new_db.get(CourseMaterial, material.id)
        assert result is not None

4. 日志增强

在关键的数据写入操作后添加日志:

await db.commit()
logger.info(f"✅ 数据已提交到数据库 - material_id: {material.id}")

📝 文档更新

已更新的文档

  1. 联调经验汇总
    文件:/root/aiedu/考培练系统规划/全链路联调/联调经验汇总.md
    内容:详细记录了问题的发现、分析和修复过程

  2. 规范与约定-团队基线
    文件:/root/aiedu/考培练系统规划/全链路联调/规范与约定-团队基线.md
    内容:新增"数据库事务管理规范"章节

  3. 本修复报告
    文件:/root/aiedu/资料上传数据库持久化问题修复报告.md
    内容:完整的问题分析和修复记录


🔗 相关链接

  • 问题页面https://aiedu.ireborn.com.cn/manager/edit-course/1
  • 后端代码/root/aiedu/kaopeilian-backend/app/services/course_service.py
  • 前端代码/root/aiedu/kaopeilian-frontend/src/views/manager/edit-course.vue
  • API文档POST /api/v1/courses/{course_id}/materials

📞 联系方式

如有问题或发现类似Bug请联系开发团队

  • 数据库连接:120.79.247.16:3307
  • 数据库名:kaopeilian
  • 管理员账号:root / nj861021

修复状态 已完成
验证状态 待用户测试
文档更新 已完成
规范制定 已完成


本报告由AI助手生成已经过人工审核。