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

如何在Spring Data JPA中通过单查询获取多表关联结果?

为什么你的NativeQuery会生成两条查询?

这种情况我之前也碰到过,大概率是你的AddressData实体类中存在与Address的关联映射(比如@ManyToOne或@OneToOne),并且该关联的fetch类型为EAGER——很多关联注解的默认fetch类型就是EAGER,比如@ManyToOne,这就是问题的根源。

当你用createNativeQuery(query, AddressData.class)把原生查询结果映射到实体类时,Hibernate会先执行你写的内连接SQL获取address_data的数据,但因为关联的Address对象是EAGER加载模式,它会额外触发一条查询去拉取每个AddressData对应的Address记录,最终就出现了两条查询语句。

几个可行的解决方法

方法1:把关联改成懒加载(LAZY)

如果你的业务场景里不需要每次都加载Address对象,直接修改AddressData中的关联注解,设置fetch = FetchType.LAZY就行:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ad_id") // 根据你的实际关联字段调整
private Address address;

这样Hibernate只会在你实际调用AddressData.getAddress()时才会触发查询,而不是默认就加载关联对象。

方法2:用DTO接收结果(推荐不需要实体关联时用)

如果你的需求只是获取address_data的部分或全部数据,不需要关联的Address实体,可以定义一个简单的DTO类,让原生查询直接映射到DTO:

// 定义一个简单的DTO
public class AddressDataDTO {
    private Long adId;
    private String addressLine;
    // 其他你需要的字段

    // 注意:构造方法的参数顺序要和查询结果的列顺序完全一致
    public AddressDataDTO(Long adId, String addressLine) {
        this.adId = adId;
        this.addressLine = addressLine;
    }

    // getter和setter按需添加
}

// 对应的查询代码
String query = "Select ad.ad_id, ad.address_line from address_data ad inner join address a ON a.ad_id = ad.ad_id where a.address = :address";
Query q = entityManager.createNativeQuery(query)
    .setResultTransformer(new AliasToBeanResultTransformer(AddressDataDTO.class));
q.setParameter("address", address);
List<AddressDataDTO> permitList = q.getResultList();

方法3:用@SqlResultSetMapping同时加载关联数据(如果确实需要关联对象)

如果你必须同时获取AddressData和对应的Address,可以通过@SqlResultSetMapping定义结果映射,让Hibernate一次性从原生查询中拿到所有数据,避免额外查询:

// 在AddressData实体类上添加映射定义
@Entity
@SqlResultSetMapping(
    name = "AddressDataWithAddress",
    entities = {
        @EntityResult(entityClass = AddressData.class),
        @EntityResult(entityClass = Address.class)
    }
)
public class AddressData {
    // 你的实体字段和关联映射代码
}

// 查询代码
String query = "Select ad.*, a.* from address_data ad inner join address a ON a.ad_id = ad.ad_id where a.address = :address";
Query q = entityManager.createNativeQuery(query, "AddressDataWithAddress");
q.setParameter("address", address);
List<Object[]> results = q.getResultList();

// 从结果数组中提取实体并关联
List<AddressData> permitList = new ArrayList<>();
for (Object[] result : results) {
    AddressData ad = (AddressData) result[0];
    Address a = (Address) result[1];
    ad.setAddress(a); // 手动把Address关联到AddressData上
    permitList.add(ad);
}

这样Hibernate只会执行一次原生查询,同时返回两个实体的数据,你只需要手动关联它们就可以了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:25:38