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

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

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

学习

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

更多

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

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Java 生态与工具链/课时/Hibernate 深入
RawBlame
课时目录12 节

Java 生态与工具链

  1. 01Java 生态地图
  2. 02数据库访问
  3. 03Hibernate 深入
  4. 04EBean ORM
  5. 05日志框架
  6. 06Javadoc 与文档
  7. 07Play Framework
  8. 08Javalin 微框架
  9. 09REST Assured
  10. 10JMeter 性能测试
  11. 11Java 加密基础
  12. 12综合练习

Hibernate 深入

hibernate 节点;衔接 orm-jpa。

35 分钟

Hibernate 深入

orm-essentials 教了 @Entity 与 EntityManager 的入门用法;本课补 Session 生命周期、懒加载陷阱、N+1 与二级缓存 等 Hibernate 特有细节,让你在 spring-boot-essentials 里不再「注解会写、SQL 爆炸不懂」。

学习目标

  • 理解 Session / EntityManager 与持久化上下文(Persistence Context)
  • 识别并修复 N+1 查询与 LazyInitializationException
  • 掌握 @OneToMany fetch 策略与 join fetch 的取舍

实体与关系映射

@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String code;

    @OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<OrderItem> items = new ArrayList<>();

    public void addItem(OrderItem item) {
        items.add(item);
        item.setOrder(this);
    }
}

@Entity
@Table(name = "order_items")
public class OrderItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String sku;
    private int qty;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id")
    private Order order;
}

双向关联时由「拥有外键的一方」维护关系;mappedBy 侧只读映射。

N+1 与 join fetch

// 坏味道:查 1 条 Order,再懒加载 N 次 items → N+1
Order order = em.find(Order.class, 1L);
order.getItems().size();

// 修复:一次 JPQL 拉齐
List<Order> orders = em.createQuery(
    "select distinct o from Order o join fetch o.items where o.code = :code",
    Order.class)
    .setParameter("code", "ORD-001")
    .getResultList();
现象原因对策
LazyInitializationExceptionSession 已关仍访问懒集合@Transactional 内完成访问,或 DTO 投影
日志里 1+N 条 SELECT默认 LAZY + 循环触达join fetch / @EntityGraph / batch size
distinct 重复行join 笛卡尔积JPQL 加 distinct,或改 DTO 查询

Session 与 Spring 事务

Hibernate 的 Session 在 JPA 下由 EntityManager 包装。Spring 的 在方法入口绑定 Session、出口 flush 并关闭——。

@Transactional
事务边界 = 持久化上下文边界
@Service
public class OrderService {
    @PersistenceContext
    private EntityManager em;

    @Transactional(readOnly = true)
    public OrderDto getOrder(String code) {
        Order order = em.createQuery(/* join fetch */, Order.class)
            .setParameter("code", code)
            .getSingleResult();
        return OrderDto.from(order); // 在事务内完成映射
    }
}

练习

  • 开启 hibernate.show_sql,复现一次 N+1,再用 join fetch 对比 SQL 条数
  • 写一个会触发 LazyInitializationException 的测试,并用 @Transactional 修复
  • 阅读 java-core-essentials 的异常处理,为 NonUniqueResultException 设计友好错误

小结

Hibernate 的威力在对象图导航,代价是 SQL 不可见。 掌握 Session 边界与 fetch 策略,ORM 才是助力而非黑盒。下一课看轻量替代方案 EBean。

加载本节练习…
← 上一课数据库访问下一课 →EBean ORM