本文介绍了Java Spring JPA FetchMode.JOIN不使用JOIN的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Spring中,我使用JPA的模型结构非常复杂。当使用Spring Data查询我的数据库时,我期待使用JOINS检索数据的一个查询,而Spring正在运行多个查询。以下是我的模型结构:

供稿属性:

  public class FeedAttribute {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name =feedAttributeId,nullable = false)
private Integer feedAttributeId;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =feedId,nullable = false)
私人饲料饲料;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =sourceEntityAttributeId,nullable = false)
私人EntityAttribute sourceEntityAttribute;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =targetEntityAttributeId,nullable = false)
私有EntityAttribute targetEntityAttribute;

$ b

Feed:

  public class Feed {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name =feedId,nullable = false,length = 100)
private Integer feedId;

@Column(name =feedName,nullable = false,length = 100)
private String feedName;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =releaseId,nullable = false)
私人发布版本;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =sourceSystemId,nullable = false)
专用系统源系统;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =targetSystemId,nullable = false)
专用系统目标系统;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =companyId,nullable = false)
私人公司公司;

$ b

实体属性: p>

  public class EntityAttribute {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name =entityAttributeId,nullable = false)
private Integer entityAttributeId;

@Column(name =entityCode,nullable = false,length = 100)
private String entityCode;

@Column(name =attributeCode,nullable = false,length = 100)
private String attributeCode;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =dataModelId,nullable = false)
private DataModel dataModel;

$ b

数据模型:

  public class DataModel {

@Id
@Column(name =dataModelId,nullable = false)
private String dataModelId;

@Column(name =dataModelDescription,nullable = false)
private String dataModelDescription;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =companyId,nullable = false)
私人公司公司;

$ b

系统:

  public class System {

@Id
@Column(name =systemId,nullable =假,长度= 100)
private String systemId;

@Column(name =systemName,nullable = false)
private String systemName;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =systemSubType,nullable = true)
私有SystemSubType systemSubType;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =systemType,nullable = false)
私有SystemType systemType;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =companyId,nullable = false)
私人公司公司;

$ b

发布:

  public class Release {

@Id
@Column(name =releaseId,nullable =假,长度= 100)
private String releaseId;

@Column(name =releaseDescription,nullable = false,length = 1000)
private String releaseDescription;

@Column(name =releaseDate)
private日期releaseDate = new Date();

@Column(name =releaseLocation,nullable = false)
private String releaseLocation;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value = FetchMode.JOIN)
@JoinColumn(name =companyId,nullable = false)
私人公司公司;


$ / code>

你得到图片 - 我不会继续添加模型。我正在使用spring数据运行此查询:

  feedAttributeRepository.findByFeed(feed); 

这将查询给定提要的所有提要属性。现在,我希望发生的事情是对feedAttribute表运行查询,两次加入entityAttribute并加入feed。然后,我会期待feed中的后续嵌套值也被连接(system,release),并且嵌套在entityAttribute(dataModel)中的值也将被连接 - 以此类推,对于我指定的所有FetchMode.JOIN。 p>

事实上,实际发生的事情是,spring运行多个select查询,其中一些正在加入,另一些则不在。在我的情况下,entityAttribute对象没有被连接到feedAttribute对象上。通过为每个返回的feedAttribute运行多个SELECT语句来检索它们。大约有300-400个feedAttributes被返回,你可以想象,这是非常低效的。



JOIN的数量是否有上限?或者JPA正在研究这是检索数据的最佳方法吗?正如我所理解的,许多联接也可能效率低下。谢谢

它正在使用MySQL,但我正在转向Oracle,整个事情因为我执行的SELECT语句的数量超出了数据库上的游标而全部中断。一个噩梦!

解决方案

您似乎在这里遇到了一个误解:对一个对象的懒/当通过主键加载对象时(即通过 EntityManager.find(id,type) FeedAttributeRepository.findOne(id)为查询执行禁用全局提取计划。



对于查询方法,您显式地必须在查询定义中指定提取连接(这将需要手动声明的查询)或使用 @EntityGraph 定义一个用于查询方法的提取图形(请参阅)。


I have quite a complicated model structure in Spring using JPA. When using Spring Data to query my database I am expecting ONE query that uses JOINS to retrieve the data, instead Spring is running multiple queries. Below is my model structure:

Feed Attribute:

public class FeedAttribute {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="feedAttributeId", nullable=false)
private Integer feedAttributeId;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="feedId", nullable=false)
private Feed feed;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="sourceEntityAttributeId", nullable=false)
private EntityAttribute sourceEntityAttribute;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="targetEntityAttributeId", nullable=false)
private EntityAttribute targetEntityAttribute;

}

Feed:

public class Feed {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="feedId", nullable=false, length=100)
private Integer feedId;

@Column(name="feedName", nullable=false, length=100)
private String feedName;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="releaseId", nullable=false)
private Release release;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="sourceSystemId", nullable=false)
private System sourceSystem;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="targetSystemId", nullable=false)
private System targetSystem;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="companyId", nullable=false)
private Company company;

}

Entity Attribute:

public class EntityAttribute {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="entityAttributeId", nullable=false)
private Integer entityAttributeId;

@Column(name="entityCode", nullable=false, length=100)
private String entityCode;

@Column(name="attributeCode", nullable=false, length=100)
private String attributeCode;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="dataModelId", nullable=false)
private DataModel dataModel;

}

Data Model:

public class DataModel {

@Id
@Column(name="dataModelId", nullable=false)
private String dataModelId;

@Column(name="dataModelDescription", nullable=false)
private String dataModelDescription;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="companyId", nullable=false)
private Company company;

}

System:

public class System {

@Id
@Column(name="systemId", nullable=false, length=100)
private String systemId;

@Column(name="systemName", nullable=false)
private String systemName;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="systemSubType", nullable=true)
private SystemSubType systemSubType;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="systemType", nullable=false)
private SystemType systemType;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="companyId", nullable=false)
private Company company;

}

Release:

public class Release {

@Id
@Column(name="releaseId", nullable=false, length=100)
private String releaseId;

@Column(name="releaseDescription", nullable=false, length=1000)
private String releaseDescription;

@Column(name="releaseDate")
private Date releaseDate = new Date();

@Column(name="releaseLocation", nullable=false)
private String releaseLocation;

@ManyToOne(cascade = CascadeType.DETACH)
@Fetch(value=FetchMode.JOIN)
@JoinColumn(name="companyId", nullable=false)
private Company company;

}

You get the picture - I won't keep adding models. I am running this query using spring data:

feedAttributeRepository.findByFeed(feed);

Which will query all feed attributes for a given feed. Now, what I would expect to happen is run a query against the feedAttribute table, joining entityAttribute twice and joining feed. I would then expect the subsequent nested values in feed to be joined too (system, release), and the values nested within entityAttribute (dataModel) to be joined as well - and so on, for all FetchMode.JOIN that I specify.

In fact, what is actually happening, is spring is running multiple select queries, some which are joining and some which aren't. In my case the entityAttribute objects are not being joined on the feedAttribute object. They are retrieved by running multiple SELECT statements for every feedAttribute returned. There are about 300-400 feedAttributes returned so as you can imagine, this is incredibly inefficient.

Is there an upper limit on the number of JOINs that can be performed? Or is JPA working out that this is the best way to retrieve the data? As I do understand lots of JOINs can be inefficient too. Thanks

P.S. It was working using MySQL, but I'm moving over to Oracle and the whole thing breaks down because I am running out of Cursors on the Database because of the number of SELECT statements executed. A bit of a nightmare!

解决方案

You seem to run into a misconception here: lazy/eager definitions on an object are only considered when loading an object via it's primary key (i.e. via EntityManager.find(id, type) or FeedAttributeRepository.findOne(id). Hibernate disables the global fetch plan for query executions.

For query methods you explicitly have to specify fetch joins in the query definition (which will require a manually declared query) or define an fetch graph to be used for the query method using @EntityGraph (see the reference documentation for details).

这篇关于Java Spring JPA FetchMode.JOIN不使用JOIN的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 08:31