【发布时间】:2023-11-07 11:31:01
【问题描述】:
Media 实体和MediaAnalysis 实体之间存在一对一的关系,其中Media 实体是一个抽象基类:
新闻报道实体
@Entity
@DiscriminatorValue("N")
public class NewsReport extends Media {
@Column(name = "BODY", nullable = false)
private String body;
NewsReport(){}
public NewsReport(String title, String link, String author, String body) {
super(title, link, author);
this.body= body;
}
public String getBody() {
return body;
}
}
媒体实体
@Entity
@Inheritance(
strategy = InheritanceType.SINGLE_TABLE
)
@DiscriminatorColumn(name = "TYPE", length = 1, discriminatorType = DiscriminatorType.STRING)
public abstract class Media {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
@Column(name = "TITLE", nullable = false)
private String title;
@Column(name = "LINK", length = 500, nullable = false)
private String link;
@Column(name = "AUTHOR", length = 45, nullable = false)
private String author;
@OneToOne(mappedBy = "media")
private MediaAnalysis analysis;
Media(){}
public Media(String title, String link, String author) {
this.title = title;
this.link = link;
this.author = author;
}
// getters
public Optional<MediaAnalysis> getAnalysis() {
return Optional.ofNullable(analysis);
}
}
媒体分析
@Entity
public class MediaAnalysis {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
@Column(name = "SUCCESS", nullable = false)
private Boolean success;
@OneToOne
@JoinColumn(
name = "MED_ID",
nullable = false,
foreignKey = @ForeignKey(name="MEA_MED_FK")
)
private Media media;
@Column(name = "CONTENT", nullable = false)
private String content;
MediaAnalysis() { }
public MediaAnalysis(Media media, Boolean success, String content) {
this.media = media;
this.success = success;
this.content = content;
}
// getters
public Media getMedia() {
return media;
}
public String getContent() {
return content;
}
}
现在当我想使用我的AnalysisRepository.getByMedia(..a NewsReport...) 时
public interface AnalysisRepository extends JpaRepository<MediaAnalysis,Long> {
@Query("SELECT a FROM MediaAnalysis a LEFT JOIN FETCH a.media WHERE a.media = ?1")
Optional<MediaAnalysis> getByMedia(Media media);
}
例如,要通过NewsReport 查找MediaAnalysis,我希望hibernate 运行单个SELECT 查询,例如:
从媒体分析 m 中选择 m.* 其中 m.med_id = ?
但是,当我启用查询日志记录时,我看到了 2:
调试 ohSQL:92 - 选择 mediaanaly0_.id 作为 id1_0_0_,media1_.id 作为 id2_1_1_,mediaanaly0_.med_id 作为 med_id3_0_0_,mediaanaly0_.success 作为 success2_0_0_,media1_.author 作为 author3_1_1_,media1_.link 作为 link4_1_1_,media1_.title 作为title5_1_1_, media1_.body as body6_1_1_, media1_.type as type1_1_1_ from mea_media_analysis mediaanaly0_ left outer join med_media media1_ on mediaanaly0_.med_id=media1_.id where mediaanaly0_.med_id=?
TRACE o.h.t.d.s.BasicBinder:65 - 绑定参数 [1] 为 [BIGINT] - [1]
调试 ohSQL:92 - 选择 mediaanaly0_.id 作为 id1_0_1_,mediaanaly0_.med_id 作为 med_id3_0_1_,mediaanaly0_.success 作为 success2_0_1_,media1_.id 作为 id2_1_0_,media1_.author 作为 author3_1_0_,media1_.link 作为 link4_1_0_,media1_.title 作为title5_1_0_, media1_.body as body6_1_0_, media1_.type as type1_1_0_ from mea_media_analysis mediaanaly0_ inner join med_media media1_ on mediaanaly0_.med_id=media1_.id where mediaanaly0_.med_id=?
TRACE o.h.t.d.s.BasicBinder:65 - 绑定参数 [1] 为 [BIGINT] - [1]
似乎首先按预期选择了MediaAnalysis,但随后还有一个似乎不必要的查询。我可以告诉这两个查询之间的唯一区别是连接类型。我认为问题与Media 继承有关。
为什么会这样? + 我该怎么做才能确保这是一个查询?
进一步说明,如果我从存储库中删除 @Query,实际上会有 三个 查询!。
调试 ohSQL:92 - 选择 mediaanaly0_.id 作为 id1_0_,mediaanaly0_.med_id 作为 med_id3_0_,mediaanaly0_.success 作为success2_0_ from mea_media_analysis mediaanaly0_ left outer join med_media media1_ on mediaanaly0_.med_id=media1_.id where media1_.id=?
TRACE o.h.t.d.s.BasicBinder:65 - 绑定参数 [1] 为 [BIGINT] - [1]
调试 ohSQL:92 - 选择 media0_.id 作为 id2_1_0_,media0_.author 作为 author3_1_0_,media0_.link 作为 link4_1_0_,media0_.title 作为 title5_1_0_,media0_.body 作为 body6_1_0_,media0_.type 作为 type1_1_0_,mediaanaly1_.id 作为id1_0_1_, mediaanaly1_.med_id as med_id3_0_1_, mediaanaly1_.success as success2_0_1_ from med_media media0_ left outer join mea_media_analysis mediaanaly1_ on media0_.id=mediaanaly1_.med_id where media0_.id=?
TRACE o.h.t.d.s.BasicBinder:65 - 绑定参数 [1] 为 [BIGINT] - [1]
调试 ohSQL:92 - 选择 mediaanaly0_.id 作为 id1_0_1_,mediaanaly0_.med_id 作为 med_id3_0_1_,mediaanaly0_.success 作为 success2_0_1_,media1_.id 作为 id2_1_0_,media1_.author 作为 author3_1_0_,media1_.link 作为 link4_1_0_,media1_.title 作为title5_1_0_, media1_.body as body6_1_0_, media1_.type as type1_1_0_ from mea_media_analysis mediaanaly0_ inner join med_media media1_ on mediaanaly0_.med_id=media1_.id where mediaanaly0_.med_id=?
TRACE o.h.t.d.s.BasicBinder:65 - 绑定参数 [1] 为 [BIGINT] - [1]
【问题讨论】:
-
删除@Query 时看到的查询是什么?
-
@Kirinya 添加了额外的查询:)
-
你可以试试
@OneToOne(optional = false)吗?我认为JoinColumn的nullable字段仅在您自动生成表的情况下更改DDL,而不是执行的SQL -@OneToOne(optional = false)正在做什么 -
您有两种方式绑定。你就不能
aNewsReport.getAnalysis()吗? -
做这个查询的时候日志里还有其他的查询吗?当您拥有 EAGER(
@OneToOne默认为 EAGER)、FETCH、optional=false和 Inheritance 组合时,Hibernate 可以触发许多并行查询。按照查询的顺序可以帮助您理解场景。
标签: spring hibernate spring-data-jpa jpql