Home > database >  Why Spring JPA Hibernate is fetching all the records individually by id?
Why Spring JPA Hibernate is fetching all the records individually by id?

Time:07-08

I am running following query using Spring JPA in my project. Its internally using Hibernate for connecting to MySql DB. This query is written inside JpaRepository.

@Query(value = "SELECT ipd.* FROM identifier_pool_definition ipd, identifier_definition id WHERE\n"  
            "ipd.definition_id = id.definition_id AND id.acquirer_id = :acquirerId AND"  
            " id.domain = :domain AND id.definition_type = 'pool' AND id.status IN :statuses  AND id.type = :poolType  AND id.is_deleted = false",
            nativeQuery = true)
List<IdentifierPoolDefinitionEntity> findAllWithPoolTypeAndStatuses(@Param("acquirerId") String processorId,
                                                                        @Param("domain") String domain,
                                                                        @Param("poolType") String poolType,
                                                                        @Param("statuses") Collection<String> statuses);

In the application logs I am observing that after running above query, Hibernate is making individual select DB calls by id for each record fetched in the above query.

Sample logs:

Hibernate: 
    SELECT
        ipd.* 
    FROM
        identifier_pool_definition ipd,
        identifier_definition id 
    WHERE
        ipd.definition_id = id.definition_id 
        AND id.acquirer_id = ? 
        AND id.domain = ? 
        AND id.definition_type = 'pool' 
        AND id.status IN (
            ?, ?, ?
        )  
        AND id.type = ?  
        AND id.is_deleted = false
Hibernate: 
    select
        identifier0_.definition_id as definiti1_2_0_,
        identifier0_.acquirer_id as acquirer2_2_0_,
        identifier0_.created as created3_2_0_,
        identifier0_.created_by as created_4_2_0_,
        identifier0_.definition_type as definiti5_2_0_,
        identifier0_.domain as domain6_2_0_,
        identifier0_.is_deleted as is_delet7_2_0_,
        identifier0_.merchant_id as merchant8_2_0_,
        identifier0_.processor_id as processo9_2_0_,
        identifier0_.status as status10_2_0_,
        identifier0_.type as type11_2_0_,
        identifier0_.updated as updated12_2_0_,
        identifier0_.updated_by as updated13_2_0_ 
    from
        identifier_definition identifier0_ 
    where
        identifier0_.definition_id=?
...
...
after n records
...
...
Hibernate: 
    select
        identifier0_.definition_id as definiti1_2_0_,
        identifier0_.acquirer_id as acquirer2_2_0_,
        identifier0_.created as created3_2_0_,
        identifier0_.created_by as created_4_2_0_,
        identifier0_.definition_type as definiti5_2_0_,
        identifier0_.domain as domain6_2_0_,
        identifier0_.is_deleted as is_delet7_2_0_,
        identifier0_.merchant_id as merchant8_2_0_,
        identifier0_.processor_id as processo9_2_0_,
        identifier0_.status as status10_2_0_,
        identifier0_.type as type11_2_0_,
        identifier0_.updated as updated12_2_0_,
        identifier0_.updated_by as updated13_2_0_ 
    from
        identifier_definition identifier0_ 
    where
        identifier0_.definition_id=?

Following are my entity classes:

IdentifierPoolDefinitionEntity.java

@Entity
@Table(name = "identifier_pool_definition")
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class IdentifierPoolDefinitionEntity implements Serializable {

    private static final long serialVersionUID = 518449602683891708L;

    @Id
    @Column(name = "definition_id", columnDefinition = "BINARY(16)")
    private UUID definitionId;

    @Column(name = "prefix")
    private String prefix;

    @Column(name = "suffix")
    private String suffix;

    @Column(name = "formatter")
    private String formatter;

    @Column(name = "lower_bound")
    private Long lowerBound;

    @Column(name = "upper_bound")
    private Long upperBound;

    @Column(name = "`separator`")
    private String separator;

    @Column(name = "created")
    @CreationTimestamp
    @JsonSerialize(using = CustomLocalDateTimeSerializer.class)
    private LocalDateTime created;

    @Column(name = "created_by")
    private String createdBy;

    @Column(name = "updated")
    @JsonSerialize(using = CustomLocalDateTimeSerializer.class)
    private LocalDateTime updated;

    @Column(name = "updated_by")
    private String updatedBy;

    @JsonIgnore
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @PrimaryKeyJoinColumn
    private IdentifierDefinitionEntity identifierDefinitionEntity;

}

IdentifierDefinitionEntity.java

@Entity
@Table(name = "identifier_definition")
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class IdentifierDefinitionEntity implements Serializable {

    private static final long serialVersionUID = 7809377866509417398L;

    @Id
    @Column(name = "definition_id", columnDefinition = "BINARY(16)")
    private UUID definitionId;

    @Column(name = "definition_type")
    private String definitionType;

    @Column(name = "type")
    private String type;

    @Column(name = "acquirer_id")
    private String acquirerId;

    @Column(name = "domain")
    private String domain;

    @Column(name = "processor_id")
    private String processorId;

    @Column(name = "merchant_id")
    private String merchantId;

    @Column(name = "status")
    private String status;

    @Column(name = "is_deleted")
    private boolean isDeleted;

    @Column(name = "created")
    @CreationTimestamp
    @JsonSerialize(using = CustomLocalDateTimeSerializer.class)
    private LocalDateTime created;

    @Column(name = "created_by")
    private String createdBy;

    @Column(name = "updated")
    @JsonSerialize(using = CustomLocalDateTimeSerializer.class)
    private LocalDateTime updated;

    @Column(name = "updated_by")
    private String updatedBy;

    @JsonIgnore
    @OneToOne(mappedBy = "identifierDefinitionEntity", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private IdentifierPoolDefinitionEntity identifierPoolDefinitionEntity;

    @JsonIgnore
    @OneToMany(mappedBy = "identifierDefinitionEntity", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private Set<IdentifierListValuesEntity> listValues;

    @JsonIgnore
    @OneToMany(mappedBy = "identifierDefinitionEntity", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<IdentifierAssignmentEntity> identifierAssignmentEntity;
}

Driver code:

val allPoolsForProcessor = identifierPoolDefinitionRepository.findAllWithPoolTypeAndStatuses(acquirerId, domain,
                listType.getValue(), Arrays.stream(PoolStatus.values())
                        .map(PoolStatus::getValue)
                        .collect(Collectors.toList()));

I want to understand why Hibernate is showing this behaviour? Is there a way to restrict the implicit DB calls done by Hibernate?

CodePudding user response:

I think it's something related to this topic : How can I make a JPA OneToOne relation lazy Try to make the relation explicitly not-nullable and lazy so that hibernate can knows if it can makes a proxy or have to get the real entity for the field identifierDefinitionEntity on IdentifierPoolDefinitionEntity :

@OneToOne(optional = false, fetch = FetchType.LAZY)
  • Related