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

Spring Boot接口LEFT JOIN查询仅返回单条记录问题排查

问题分析与解决方案

我来帮你拆解下这个LEFT JOIN只返回1条记录的问题,核心原因其实出在实体类和查询结果的映射不匹配上,咱们一步步来看:

为什么会只返回1条记录?

你用原生SQL写了SELECT * FROM model as m LEFT JOIN role_model as rm on(m.m_id =rm.m_id),这条SQL本身是没问题的,数据库层面确实会返回3条记录,但你的Repository方法返回的是List<Model>——而Model实体只对应model表的字段,查询结果里却包含了role_model的所有字段。

这里有两个关键冲突点:

  1. 两张表都有name字段,SELECT *会返回两个name列,JPA在映射到Model实体时,会用后面的role_model.name覆盖前面的model.name;
  2. 对于未匹配到role_model的记录,role_model的所有字段都是NULL,JPA无法把这些额外的NULL字段映射到Model实体中,导致映射异常,最终只保留了能正确匹配(有role_model数据)的那条记录。

另外,你的Controller层返回类型是String,直接返回List<Model>会被Spring默认转换成字符串,这也可能导致显示上的误导,但核心问题还是Repository的映射逻辑。

怎么修改才能得到预期的3条记录?

根据你的业务需求,我给你三个可行的方案,你可以按需选择:

方案一:用DTO接收联合查询结果(最推荐)

如果需要同时获取model和role_model的字段,最好的方式是创建一个专门的DTO(数据传输对象)来接收联合查询的结果,避免实体类和查询结果的冲突。

  1. 先创建DTO类:
// 包含两张表的所需字段,注意字段名尽量避免冲突
public class ModelRoleDTO {
    private Integer mId;
    private String modelName;
    private Integer roleModelId;
    private String roleModelName;
    private Integer status;

    // 构造方法的参数顺序必须和SQL查询的字段顺序完全一致
    public ModelRoleDTO(Integer mId, String modelName, Integer roleModelId, String roleModelName, Integer status) {
        this.mId = mId;
        this.modelName = modelName;
        this.roleModelId = roleModelId;
        this.roleModelName = roleModelName;
        this.status = status;
    }

    // 别忘了添加getter方法,方便后续序列化返回
    public Integer getmId() { return mId; }
    public String getModelName() { return modelName; }
    // 其他字段的getter同理
}
  1. 修改Repository的查询方法,明确指定查询字段(避免同名冲突)并返回DTO:
@Query(value = "SELECT m.m_id, m.name, rm.id, rm.name, rm.status " +
               "FROM model as m LEFT JOIN role_model as rm ON m.m_id = rm.m_id", 
       nativeQuery = true)
List<ModelRoleDTO> listJoined();
  1. 最后修复Controller的返回类型,返回列表而不是字符串:
@GetMapping("/test")
public List<ModelRoleDTO> test(){
    return service.listJoined();
}

方案二:配置实体类的关联关系(适合需要使用实体类的场景)

如果你希望继续使用Model和RoleModel实体类,可以通过JPA的关联注解来处理LEFT JOIN的映射。

  1. 在Model实体中添加关联关系(假设是一对一关系,根据你的业务调整):
@Entity
@Table(name = "model")
public class Model {
    @Id
    @Column(name = "m_id")
    private Integer mId;
    private String name;

    // 关联RoleModel,fetch类型按需选择
    @OneToOne(mappedBy = "model", fetch = FetchType.EAGER)
    private RoleModel roleModel;

    // getter和setter
}
  1. 在RoleModel实体中添加反向关联:
@Entity
@Table(name = "role_model")
public class RoleModel {
    @Id
    private Integer id;
    @Column(name = "m_id")
    private Integer mId;
    private String name;
    private Integer status;

    // 关联Model
    @OneToOne
    @JoinColumn(name = "m_id", insertable = false, updatable = false)
    private Model model;

    // getter和setter
}
  1. 修改Repository的查询方法为JPQL(不需要原生SQL):
@Query("SELECT m FROM Model m LEFT JOIN FETCH m.roleModel")
List<Model> listJoined();

这样查询出来的Model列表会包含所有3条记录,未匹配的roleModel属性会是NULL。

方案三:只查询model表的字段(适合不需要role_model字段的场景)

如果你不需要role_model的字段,只是想确认LEFT JOIN的结果数量,可以修改原生SQL,只查询model表的字段:

@Query(value = "SELECT m.* FROM model as m LEFT JOIN role_model as rm ON m.m_id = rm.m_id", 
       nativeQuery = true)
List<Model> listJoined();

这样JPA可以正确映射所有3条model记录,因为查询结果只有model的字段,没有额外的冲突字段。

最后验证

不管用哪个方案,修改后启动项目调用/test接口,应该就能得到你预期的3条记录了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 14:23:18