大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
综合练习
把本 track 串起来:画 ER → 对照 schema → 写 JPA Entity 与 Repository → 可选 MyBatis 复杂查询。
学习目标
- 独立完成
cf_track/cf_lesson域建模 - 实现按 slug 查课含课时列表(无 N+1)
- 说明迁移与事务如何配合发布流程
任务 1:ER 与表
- 画出
cf_track1—Ncf_lesson1—Ncf_exerciseER 图 - 标出 PK、FK、
uk_track_slug - 对照
backend/src/main/resources/schema.sql核对
复习:orm-er、sql-design
任务 2:JPA 实现
// 需实现
public interface TrackRepository extends JpaRepository<Track, Long> {
@EntityGraph(attributePaths = {"lessons"})
Optional<Track> findBySlug(String slug);
}
public interface LessonRepository extends JpaRepository<Lesson, Long> {
List<Lesson> findByTrackIdAndStatusOrderByOrderIndexAsc(
Long trackId, String status);
}
Service 方法:
@Transactional(readOnly = true)
public TrackDetailDto getPublishedTrack(String slug);
TrackDetailDto 只暴露 API 需要的字段,勿直接返回 Entity 图。
任务 3:MyBatis 加分
写 Mapper:统计每门 track 的已发布 lesson 数,按 category 过滤:
SELECT t.slug, t.title, COUNT(l.id) AS lesson_count
FROM cf_track t
LEFT JOIN cf_lesson l ON l.track_id = t.id AND l.status = 'published'
WHERE t.category = #{category}
GROUP BY t.id
ORDER BY t.sort_order;
对照 sql-aggregate。
任务 4:发布事务
实现 publishTrack(trackId):
- 将 track 下所有
draftlesson 改为published - 任一步失败全部回滚
- 说明与
ON DELETE CASCADE的关系
见 orm-transactions、sb-transaction。
自检清单
- ER 图与 schema.sql 一致
-
findBySlug打开 SQL 日志,确认无 N+1 - 新增字段时写了 Flyway
V*.sql,非ddl-auto=update - 能解释 JPA 与 MyBatis 在本任务的各负责哪块
延伸
- PostgreSQL 实验:pg-spring
- 文档型对比:mongo-practice
- Spring 整合:sb-jpa、sb-jdbc
小结
ORM track 闭环:设计表 → 映射对象 → 控制抓取与事务 → 复杂 SQL 用 MyBatis。 回到 后端路线图 继续持久层节点。