Bertrand P
Bertrand P

Reputation: 889

Hibernate second level cache is not used in every case

Using Spring Boot 2, Spring Data JPA and Hibernate. I am trying to use the second level cache of Hibernate for some entities that are never updated.

In my case, the entity DocumentType is related to other entities, therefore when querying one document type, Hibernate is making 4 sql queries. When using Hibernate second level cache, the cache is used for some entities but there is still one sql query made to the database. I want to understand why the cache is not used in one case.

This is what my entities look like:

@Entity
@Table(name = "document_type")
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class DocumentType {

    @Id
    private Long id;

    @Column
    private String subtypeCode;

    @OneToOne(cascade = {CascadeType.ALL})
    private Translation translation;

    @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "business", joinColumns = @JoinColumn(name = "document_type_id"))
    @Enumerated(EnumType.STRING)
    @Column(name = "business")
    private Set<Business> businesses;

    @ManyToOne(cascade = {CascadeType.ALL})
    @JoinColumn(name = "equivalence_id")
    private Equivalence equivalence;
@Entity
@Table(name = "equivalence")
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Equivalence {

    @Id
    private Long id;

    @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
    @OneToMany(mappedBy="equivalence", fetch = FetchType.EAGER)
    private List<DocumentType> documentTypeList;

When I fetch a document type for the first time with this method:

@Repository
public interface DocumentTypeRepository extends JpaRepository<DocumentType, Long> {

    DocumentType findBySubtypeCode(String subtypeCode);

I have the following session metrics:

    1704919 nanoseconds spent preparing 4 JDBC statements;
    33284024 nanoseconds spent executing 4 JDBC statements;
    0 nanoseconds spent executing 0 JDBC batches;
    2983589 nanoseconds spent performing 4 L2C puts;
    0 nanoseconds spent performing 0 L2C hits;
    1313315 nanoseconds spent performing 3 L2C misses;

The same document type fetched a second time gives:

    27855 nanoseconds spent preparing 1 JDBC statements;
    4348289 nanoseconds spent executing 1 JDBC statements;
    0 nanoseconds spent executing 0 JDBC batches;
    14421 nanoseconds spent performing 1 L2C puts;
    182655 nanoseconds spent performing 3 L2C hits;
    0 nanoseconds spent performing 0 L2C misses;

I would like to have 0 JDBC statements the second time but it's not the case.

Upvotes: 3

Views: 2777

Answers (1)

crizzis
crizzis

Reputation: 10716

Second level cache only works when entities are retrieved by their ids, either using EntityManager.find(...) or internally when JPA needs to fetch related entities. Query results are never cached by default.

What you want is Hibernate query cache and the org.hibernate.cacheable query hint. Alternatively, you can enable Spring cache and use either the @Cacheable or @CachePut annotation.

Upvotes: 2

Related Questions