Java Eclipselink:批读取会创建大量查询
我使用eclipselink 2.6.4,我有以下实体Java Eclipselink:批读取会创建大量查询,java,sql,jpa,eclipselink,Java,Sql,Jpa,Eclipselink,我使用eclipselink 2.6.4,我有以下实体 @Entity @Table(name = "articles") public class Article { @Id @Column(name = "id") private Integer id; @Column(name = "title") private String title; @OneToMany(fetch = FetchType.EAGER,mappedBy = "
@Entity
@Table(name = "articles")
public class Article {
@Id
@Column(name = "id")
private Integer id;
@Column(name = "title")
private String title;
@OneToMany(fetch = FetchType.EAGER,mappedBy = "article")
@BatchFetch(BatchFetchType.IN)
private List<Author> authors
//+ setters and getters
}
@Entity
@Table(name = "authors")
public class Author {
@Id
@Column(name = "id")
private Integer id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "articleId")
private Article article;
@Column(name = "surname")
private String surname;
//+setters and getters
}
为什么有这么多疑问?我预计只有两个问题。我犯了什么错
编辑我又做了两次测试:
@BatchFetch(BatchFetchType.IN)
(没有向查询添加提示)@BatchFetch(BatchFetchType.IN)
,但在查询时使用了两个提示:
String queryString=“从文章e中选择e”;
Query Query=em.createQuery(queryString);
setHint(“eclipseelink.batch.type”,“IN”);
setHint(“eclipselink.batch”、“e.authors”);
query.setFirstResult(0);
query.setMaxResults(10);
List items=query.getResultList()| id | title |
-----------------
| 1 | article1 |
| 2 | article2 |
| 3 | article3 |
表中的数据作者:
| id | articleId | surname |
------------------------------
| 1 | 1 | Author1 |
| 2 | 1 | Author2 |
| 3 | 2 | Author3 |
| 4 | 2 | Author4 |
| 5 | 3 | Author5 |
| 6 | 3 | Author6 |
在每个测试中,执行6个查询:
SELECT id AS a1, title AS a2 FROM articles LIMIT ? OFFSET ? bind => [2 parameters bound]
SELECT id, surname, articleId FROM authors WHERE (articleId IN (?,?,?)) bind => [3 parameters bound]
SELECT id, title FROM articles WHERE (id = ?) bind => [1 parameter bound]
SELECT id, surname, articleId FROM authors WHERE (articleId = ?) bind => [1 parameter bound]
SELECT id, title FROM articles WHERE (id = ?) bind => [1 parameter bound]
SELECT id, surname, articleId FROM authors WHERE (articleId = ?) bind => [1 parameter bound]
根据以下文件: 因此,我猜会生成多个选择,因为缓存中没有对象。您尝试的是使用热缓存运行相同的查询
此外,根据您的要求,您也可以查看这一点。有两种方法可以设置批取
@BatchFetch(BatchFetchType.IN)
query.setHint(QueryHints.BATCH,column)代码>query.setHint(QueryHints.BATCH\u类型,BatchFetchType.IN)代码>
作者
表中添加了注释,但在文章
表中完成了带提示的查询。我不知道这背后的全部逻辑,但我建议:
@Entity
@Table(name = "articles")
public class Article {
@Id
@Column(name = "id")
private Integer id;
@Column(name = "title")
private String title;
@OneToMany(mappedBy = "article", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@BatchFetch(BatchFetchType.IN)
private List<Author> authors
//+ setters and getters
}
@Entity
@Table(name = "authors")
public class Author {
@Id
@Column(name = "id")
private Integer id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "articleId")
private Article article;
@Column(name = "surname")
private String surname;
//+setters and getters
}
Eclipse链接使用相同的:
OneToMany: LAZY
ManyToOne: EAGER
ManyToMany: LAZY
OneToOne: EAGER
@OneToMany必须是(fetch=FetchType.EAGER),而@ManyTone必须是(fetch=FetchType.LAZY) 前两个查询是基于JPQL和1:M上的batchFetch的,与预期的一样。第三个查询来自@batchFetch注释,看起来是正确的,虽然我不太明白为什么在本质上是OneToOne的东西上使用batchfetch而不是使用@JoinFetch这样的东西:我看不出在两个查询中这样做有什么好处 这看起来像EclipseLink中的一个bug,当在循环关系中涉及的一个急切的OneToOne类型映射上使用BatchFetch时-BatchFetch仅用于对集合类型的查询,并且可能会强制读取数据库而不是使用缓存。 选项包括:
EclipseLink需要构建Author.article之前的内置内存 关系
没有逻辑,因为在第二次查询之后,这些对象已经在cache.Hi中。由于分页,我使用批处理。查看我的问题和您的答案。我的答案是不要对集合使用获取联接。连接对于OneToOne和ManyToOne关系来说很好,因为它们不会更改返回的行数。批量抓取在1:1的情况下可能很有用,但可能不是您在这里的最佳选择。此外,无论如何,如果有两个选项-联合抓取和批量,我希望能够同时使用这两个选项。您误读了我的答案,因为我建议您在接受的答案中制定的解决方案。这个问题是由于循环关系和你渴望获取一切;您的设置使EL开始构建文章,从A1开始,然后是所有作者(B1、B2..)。在构建B2的过程中,需要构建尚未构建的A2,强制查询。将其中一个关系切换为惰性将解决此问题,因为当需要时,所有对象都将在缓存中-这就是您使用的方法。另一个选项是在1:1关系上使用fetch join。这也会起作用,但会迫使查询中不必要的表联接引入作者。这将导致建立作者,当它需要构建尚未构建的文章时,信息将包含在行中,因此不需要额外的查询。如前所述,这些数据已经存在,只是1:1的批处理机制没有寻找它,应该作为一个bug进行归档。有关
@BatchFetch vs@JoinFetch
和查询优化的更多信息,我尝试了两个测试:1)我对作者2只使用了注释@BatchFetch(BatchFetchType.IN)
。结果相同-6个查询。请用最新的更改和结果更新您的问题。现在很难说是怎么回事了。FetchType。EAGER
你能删除或改成LAZY
(LAZY
=需要时取EAGER
=立即取)问题解决了@OneToMany
必须是(fetch=FetchType.EAGER)
,@ManyToOne
必须是(fetch=FetchType.LAZY)
。在本例中,我只有两个查询,尽管Author类中的article不是null。把它作为答案,我会接受你给我的暗示。
When using BatchFetchType=IN, EclipseLink selects only objects not already in the cache. This method may work better with cursors or pagination, or in situations in which you cannot use a JOIN. On some databases, this may only work for singleton IDs.
@Entity
@Table(name = "articles")
public class Article {
@Id
@Column(name = "id")
private Integer id;
@Column(name = "title")
private String title;
@OneToMany(mappedBy = "article", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@BatchFetch(BatchFetchType.IN)
private List<Author> authors
//+ setters and getters
}
@Entity
@Table(name = "authors")
public class Author {
@Id
@Column(name = "id")
private Integer id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "articleId")
private Article article;
@Column(name = "surname")
private String surname;
//+setters and getters
}
String queryString="SELECT e FROM Article e";
Query query = em.createQuery(queryString);
query.setHint("eclipselink.batch.type", "IN");
query.setHint("eclipselink.batch", "e.authors");
query.setFirstResult(position);
query.setMaxResults(amount);
List<Article> items=query.getResultList();
OneToMany: LAZY
ManyToOne: EAGER
ManyToMany: LAZY
OneToOne: EAGER
OneToMany: LAZY
ManyToOne: EAGER
ManyToMany: LAZY
OneToOne: EAGER