You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring MapStruct如何获取懒加载实体字段信息?

问题描述

我有两个存在ManyToOne关联且采用懒加载(FetchType.LAZY)的实体:

@Entity
public class Item {
 private Long id;
 private String title;

 @ManyToOne(fetch = FetchType.LAZY)
 private Category category;
}

@Entity
public class Category {
 private Long id;
 private String title;
}

同时定义了DTO:

public class ItemDTO {
 private Long id;
 private String title;

 private Long categoryId;
}

从数据库获取Item后,使用MapStruct将其映射为ItemDTO,映射规则如下:

@Mapping(source = "category.id", target = "categoryId")
ItemDTO itemToItemDTO(Item item);

一切运行正常,但我有个疑问:MapStruct在其实现类中是如何以及从何处获取懒加载的category的信息?我已在配置中开启show-sql: true,但映射时并未看到额外的SQL查询,能否解释其工作原理?

原理解释
  • Hibernate懒加载代理的特性:当通过JPA加载Item时,因为category是懒加载关联,Hibernate不会直接查询并实例化真实的Category对象,而是返回一个动态生成的代理类对象(比如Category$HibernateProxy)。这个代理对象会持有关联实体的id值(来自Item表中存储的外键),但不会加载Category的其他属性。
  • MapStruct的直接调用逻辑:MapStruct生成的实现类代码,本质就是直接调用item.getCategory().getId()。而调用代理对象的getId()方法时,不需要触发懒加载——因为代理对象本身已经保存了这个外键值,无需去数据库查询完整的Category实体。
  • 为什么没有额外SQL:只有当调用代理对象的其他非getId类方法(比如getTitle())时,Hibernate才会触发懒加载查询,去数据库拉取完整的Category数据。而这里只获取id,完全不需要触发数据库操作,所以show-sql不会输出额外查询语句。

你可以做个简单验证:打印item.getCategory().getClass(),会看到输出的是Hibernate的代理类而非真实的Category类;如果把映射规则改成source = "category.title",此时就会触发懒加载,show-sql就能看到对应的查询语句了。

内容的提问来源于stack exchange,提问作者Nicenick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 13:52:07