CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
ORM 与数据库设计/课时/反模式
RawBlame
课时目录12 节

ORM 与数据库设计

  1. 01ORM 是什么
  2. 02范式与规范化
  3. 03ER 模型
  4. 04JPA 与 Hibernate
  5. 05MyBatis
  6. 06Spring Data 家族
  7. 07Schema 迁移
  8. 08N+1 与抓取策略
  9. 09MariaDB 与 MySQL
  10. 10ORM 与事务
  11. 11反模式
  12. 12综合练习

反模式

贫血模型、上帝 Entity、过度 ORM。

25 分钟

反模式

ORM 能提效,也能把项目拖进 贫血模型、上帝 Entity、隐式 SQL 风暴。识别反模式比背注解更重要。

学习目标

  • 列举常见 ORM 反模式及后果
  • 对照 CodeRoadMap 域模型应如何划分
  • 知道何时退回 SQL / MyBatis

贫血模型

Entity 只有 getter/setter,业务全堆在「Service 上帝类」:

// 反模式:Track 无行为,TrackService 3000 行
track.setStatus("published");
lesson.setStatus("published");
progressRepository.deleteByTrackId(id);

改进:适度 富领域模型——简单规则放 Entity(如 lesson.markPublished()),跨聚合用 Domain Service + @Transactional。

上帝 Entity

一张表 50 个字段、10 种 @OneToMany,任何接口都 findById 拉全图:

@Entity
public class Track {
    // cf_track 字段 + 冗余统计 + 临时 DTO 字段 ...
    @OneToMany private List<Lesson> lessons;
    @OneToMany private List<Progress> progresses;
    @OneToMany private List<Comment> comments;  // 列表页全加载
}

改进:读模型 DTO、分页、专用查询(见 orm-nplus1);cf_track 与 cf_progress 不必每次绑定加载。

过度 ORM

反模式后果
全局 EAGER列表接口 SQL 爆炸
循环里 save()N 次 INSERT
JPQL 拼字符串动态 SQL难维护,不如 MyBatis
ddl-auto=update 上生产不可控 DDL

报表、复杂聚合:MyBatis 或原生 SQL(orm-mybatis),别硬写 HQL。

双轨模型打架

同一 cf_lesson 既用 JPA Entity 又用 MyBatis DTO,字段名不一致——改表漏改一半。

约定:每表一个权威域对象;MyBatis resultMap 映射到同一 POJO 或明确只读 DTO。

忽视 SQL 与索引

ORM 生成 SELECT *、缺索引的 WHERE——本地数据少不觉,上线全表扫。

养成看 慢查询日志 的习惯,回到 sql-index。

相关课程

  • orm-nplus1
  • sql-design
  • mongo-vs-sql — 别用错存储

练习

  • 在 backend 找一处 Service 超过 200 行,思考能否拆域
  • 设计「课程列表 API」应用哪些 fetch 策略、哪些 DTO
  • 举一条应用 MyBatis 而非 JPA 的本站 SQL

小结

ORM 是工具不是架构;表设计 + SQL 能力仍是底线。 下一课综合练习 Track/Lesson。

加载本节练习…
← 上一课ORM 与事务下一课 →综合练习