当前位置: 首页 > 知识库问答 >
问题:

Eclipselink:批读取创建了大量查询

荆学民
2023-03-14

我使用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 = "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
}

这是我用来阅读所有文章及其作者的代码:

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();

在DB中,我有3篇文章,每篇文章都有两个作者。这些是eclipse link执行的查询:

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 IN (?,?)) bind => [2 parameters bound]
SELECT id, surname, articleId FROM authors WHERE (articleId = ?) bind => [1 parameter bound]
SELECT id, surname, articleId FROM authors WHERE (articleId = ?) bind => [1 parameter bound]

为什么有这么多疑问?我预计只有两个问题。我错在哪里?

编辑
我又做了两个测试:

>

  • 我只在文章类中对字段作者使用了注释@BatchFetch(batchfechtype.IN)(不向查询添加提示)
  • 我没有使用注释@BatchFetch(BatchFetchType.IN),但在查询中使用了两个提示:

    查询=em.createQuery(queryString);query.setHint("eclipselink.batch.type","IN");query.setHint("eclipselink.batch","e.authors");query.setFirstResult(0);query.setMaxResults(10);列表项=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]
    
  • 共有3个答案

    戴瑞
    2023-03-14

    根据@BatchFetch的留档

    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.
    

    所以我猜生成多个选择是因为缓存中没有对象。您尝试的是也使用热缓存运行相同的查询。

    此外,根据你的观点,你也可以看看这个问题。

    谯嘉胜
    2023-03-14

    前2个查询如预期的那样基于JPQL和1: M上的batchFetch。第3个来自@BatchFetch注释,似乎是正确的,尽管我不太明白为什么您会在本质上是OneToOne的东西上使用batchfetch而不是使用像@JoinFetch这样的东西:我看不出在两个查询中这样做有什么好处。

    当在循环关系中涉及的急切的一对一类型映射上使用 BatchFetch 时,这看起来像是 EclipseLink 中的一个错误 - BatchFetch 仅用于对集合类型的查询,并且可能强制读取数据库而不是使用缓存。选项包括:

      < li >使一端懒惰,以便在EclipseLink需要建立Author.article关系之前,所有文章实例将完全< br >建立在内存中。 < li >删除@BatchFetch(BatchFetchType。在)关于多对一的关系。当其他查询需要时,使用@FetchJoin或查询提示来指定BatchFetch:这个查询不需要这两个选项。
    充小云
    2023-03-14

    有两种方法可以设置批处理获取。

    1. 过度注释@BatchFetch(BatchFetchType.IN)
    2. Over query hints query.setHint(QueryHints.BATCH, column); query.setHint(QueryHints.BATCH_TYPE, BatchFetchType.IN);

    在您的例子中,我看到您在作者表中添加了注释,但在Article表中完成了带有提示的查询。我不知道这背后的全部逻辑,但我建议:

    @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();
    

    还有一点:在JPA 2.0规范中,默认情况是这样的:

    OneToMany: LAZY
    ManyToOne: EAGER
    ManyToMany: LAZY
    OneToOne: EAGER
    

    Eclipse链接使用相同的:

    OneToMany: LAZY
    ManyToOne: EAGER
    ManyToMany: LAZY
    OneToOne: EAGER
    

    @OneToMany必须是(fetch = FetchType。EAGER)和@ManyToOne必须是(fetch = FetchType。懒)。

     类似资料:
    • 我正在将AsposePdf的使用替换为itext7。并且我需要阅读一个pdf文档的CreateDate属性与itext7库以及。 就目前而言,我是这样实施的: 但我不确定这是否是阅读Createdate这样的属性的正确方法。理论上:在pdf文档的不同版本中,CreateDate可能是在不同的地方编写的。或者XMP部分的XML结构可能会被更改。 因此,我希望iText7处理了提取CreateDate

    • 读取专题信息 调用地址 http://api.bilibili.cn/sp 参数 字段 必选 类型 说明 spid false int 专题编号 title false string 专题名称 返回 返回值字段 字段类型 字段说明 spid int 专题SPID title string 专题名 pubdate int 发布日期 (UNIX Timestamp) create_at date 发布

    • 本文向大家介绍Django如何批量创建Model,包括了Django如何批量创建Model的使用技巧和注意事项,需要的朋友参考一下 1.前言: 将测试数据全部敲入数据库非常繁琐,而且如果与合作伙伴一起开发,部署,那么他们肯定也不想把时间花在一个一个录入数据的繁琐过程中,这时候,创建一个批量录入数据的脚本(population script)就非常有必要。 2.代码: 假设在models.py中定义

    • 有没有办法为Spring的NamedParameterJdbcTemplate对象设置批处理大小? 在我的项目中,我遇到了一些OutOfMemory问题,但我能够通过在一个较小的块循环中调用NamedParameterJdbcTemplate来解决它。但这需要一些额外的努力,比如确定块大小,将一个大列表拆分成更小的子列表等等。 我想知道NamedParameterJdbcTemplate是否有这样

    • 想象一下,如果我有这段代码: 那么下面这样做可以吗? 我不知道,我刚买了鲍勃叔叔的《清洁守则》,我开始质疑自己。

    • 接口说明 查询符合条件的所有素材信息 如需调用,请访问 开发者文档 来查看详细的接口使用说明 该接口仅开放给已获取SDK的开发者 API地址 POST /api/server/1.0.0/query 是否需要登录 是 请求字段说明 参数 类型 请求类型 是否必须 说明 keyWord string form 否 关键字如果为""表示差全部,有值时根据关键字查询 type int form 否 数据