0

When using @Cacheable annotation(org.springframework.cache.annotation.Cacheable) on the repository with custom key like name,getting the issue of running extra query on id field on every consecutive request.

See the repository code below:

public interface StatusRepository extends JpaRepository<Status, Integer> {

    @Cacheable(value = "StatusByStatusNameCache" , key="#statusName")
    public Status findByStatusName(String statusName);

}

Above you can see that a cache is defined for status name only, now after running first request got the following Hibernate console with query on status name:

Hibernate: select status0_.status_id as status_i1_7_, status0_.status_name as status_n2_7_ from status status0_ where status0_.status_name=?
Hibernate: select event0_.event_id as event_id1_3_, event0_.event_name as event_na2_3_ from events event0_ where event0_.event_name=?

now then hit another second request getting hibernate query in console with id :

Hibernate: select event_.event_id, event_.event_name as event_na2_3_ from events event_ where event_.event_id=?
Hibernate: select requestcha_.request_channel_id, requestcha_.request_channel_name as request_2_6_ from request_channels requestcha_ where requestcha_.request_channel_id=?
Hibernate: select status_.status_id, status_.status_name as status_n2_7_ from status status_ where status_.status_id=?

I don't understand why this extra query is firing as status_name query is cached but how to stop this id query on every consecutive call after first request.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
Rohan Dodeja
  • 296
  • 1
  • 5
  • 18

1 Answers1

2

The @Cacheable annotation by Spring is completely independent from the any cache provided by Hibernate/your JPA implementation.

The query by id will not be prevented by caching the result of the by name query, because the caching for the id query would be done by JPAs first level cache, which doesn't know or care about Springs cache.

Here is what is probably going on:

  1. findbyName

    entity is in 1st level cache and in Springs cache.

  2. Any access by id (e.g. navigating to the entity)

    entity gets served from 1st level cache.

  3. session ends.

    entity is removed from 1st level cache

  4. findByName

    entity is served from Springs cache. Note that this is now a detached entity. Nothing is in the 1st level cache.

  5. access by id

    entity is loaded from database, since it is not found in the 1st level cache.

You should enable Hibernates 2nd level cache to cache entities across sessions for access by id.

I also would advise against combining the caches of JPA/Hibernate with Spring Caches and rather use JPAs own query cache to cache findByName. See Spring JPA Hibernate query cache doesn't work for how to make it work with Spring Data JPA.

Also take a look at this article by Vlad Mihalcea about interaction of query cache and 2nd level cache.

Note that Oliver Drotbohm seems to have a different opinion.

Community
  • 1
  • 1
Jens Schauder
  • 77,657
  • 34
  • 181
  • 348