@BatchSize但在@ManyToOne案例中有很多往返

You*_*sef 5 java performance spring hibernate jpa

我使用hibernate spring-data-jpa和querydsl进行分页,并且我只使用@BatchSize(size=10)一次数据库往返.

@Entity
@Table(name = "appel_offre", catalog = "ao")
public class AppelOffre implements java.io.Serializable {

    ....
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "appelOffre")
    @BatchSize(size=10)
    public Set<AoActivite> getAoActivites() {
        return this.aoActivites;
    }
Run Code Online (Sandbox Code Playgroud)

并且:

@Entity
@Table(name = "ao_activite", catalog = "ao")
public class AoActivite implements java.io.Serializable {
    .....
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ID_ACTIVITE", nullable = false)
    @BatchSize(size=10)
    public Activite getActivite() {
        return this.activite;
    }
Run Code Online (Sandbox Code Playgroud)

我的查询

JPAQuery query = new JPAQuery(entityManager).from(ao) 

    .leftJoin( ao.acheteur, ach ).fetch()

    .leftJoin( ao.aoActivites , ao_ac )
    .leftJoin( ao_ac.activite , ac )
    .offset(...).limit(...).list(..);
Run Code Online (Sandbox Code Playgroud)

但是在日志中有很多往返数据库:

1 - round-trip

.....
Hibernate: select ... from ao.ao_activite aoactivite0_ where aoactivite0_.ID_APPEL_OFFRE in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: select ... from ao.activite activite0_ where activite0_.ID_ACTIVITE=?
Hibernate: select ... from ao.activite activite0_ where activite0_.ID_ACTIVITE=?

2 - round-trip

.....
Hibernate: select ... from ao.activite activite0_ where activite0_.ID_ACTIVITE=?
Hibernate: select ... from ao.activite activite0_ where activite0_.ID_ACTIVITE=?
Hibernate: select ... from ao.activite activite0_ where activite0_.ID_ACTIVITE=?

3 - round-trip

.....
Hibernate: select ... from ao.activite activite0_ where activite0_.ID_ACTIVITE=?
Hibernate: select ... from ao.activite activite0_ where activite0_.ID_ACTIVITE=?

4 - round-trip

.....
Hibernate: select ... from ao.activite activite0_ where activite0_.ID_ACTIVITE=?

5 - round-trip

.....

6 - round-trip

.....
Hibernate: select ... from ao.activite activite0_ where activite0_.ID_ACTIVITE=?

7 - round-trip

......

8 - round-trip

.....
Hibernate: select ... from ao.activite activite0_ where activite0_.ID_ACTIVITE=?

9 - round-trip

.....

10 - round-trip
Run Code Online (Sandbox Code Playgroud)

Rad*_*ler 8

该@BatchSize有道理两个

  • One-To-Many 和
  • Many-to-One 同样

就我而言Many-To-One,我们必须在@Entity级别上应用它(在我们的例子中对Activite类的映射)

@Entity
@BatchSize(size=25)
@Table(name = "activite" ...
public class Activite implements java.io.Serializable {
...
Run Code Online (Sandbox Code Playgroud)

在doc中查看(下面附带的小引号):

20.1.5.使用批量提取

...

批量获取类/实体更容易理解.请考虑以下示例:在运行时,您在会话中加载了25个Cat实例,并且每个实例Cat都有一个对其所有者的引用,即Person.在Person类的映射使用了代理服务器,为lazy ="真".如果您现在遍历所有猫并对getOwner()每个猫进行调用,默认情况下,Hibernate将执行25个SELECT语句来检索代理所有者.您可以通过在Person的映射中指定批量大小来调整此行为:

<class name="Person" batch-size="10">...</class>
Run Code Online (Sandbox Code Playgroud)

...


Vla*_*cea 6

  1. @BatchSize对于多对象(例如@OneToMany)更有意义,而不是对一对一的关系.

  2. 对于批量提取,您有(M/N + 1)个数据库往返,其中M是未初始化的多对多关联中的子实体数,N是批量大小.

  3. 如果只需要一个辅助数据库往返,则需要使用子选择提取.

  4. 对于一对一关联(例如@ManyToOne),请使用JPQL或Criteria JOIN FETCH.