Entity not returned from L1 cache

余生颓废 提交于 2021-02-11 07:19:45

问题


We are using Spring JPA in our project without any L2 cache. As per the docs, within a session, the related entities are returned from the L1 cache.

To test this out, in application.yml I enabled the query generation

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

In the implementation class, I added the following two lines of code.

Employee emp1 = employeeRepository.getByEmployeeCode(empCode);
Employee emp2 = employeeRepository.getByEmployeeCode(empCode);

I was hoping to see the query printed only once. But to my surprise, the query was printed twice on the console.

Then I assumed that the query is just generated multiple times irrespective of from where the entity is picked. But in this article about L2 cache, it is mentioned that the query is generated only once if the entity is present in the L2 cache. And I quote

You could also enable logging of SQL generated by Hibernate and invoke fooService.findOne(foo.getId()) multiple times in the test to verify that the select statement for loading Foo is printed only once (the first time), meaning that in subsequent calls the entity instance is fetched from the cache.

I am confused and I would like to the reason for this behavior? TIA.


回答1:


By default an entity will be retrieved from the first level cache only when you try to obtain the entity by id.

Example:

// first time the entity will be retrieved from DB
// under the hood it calls EntityManager.find method
Optional<Employee> employee1 = employeeRepository.findById(1L);

// here the entity will be retrieved from L1
Optional<Employee> employee2 = employeeRepository.findById(1L);

When you call the method:

Employee emp2 = employeeRepository.getByEmployeeCode(empCode);

actually spring data jpa generates and runs some HQL for you, but HQL is not cached by default. So you should do some additional things.

You can use @Cacheable annotation for caching your employeeRepository.getByEmployeeCode method:

import org.springframework.cache.annotation.Cacheable;

public interface EmployeeRepository extends CrudRepository<Employee, Long>
{
   @Cacheable("employeeByCode")
   List<Employee> getByEmployeeCode(String name);

}

This is also assume that you have configured cache manager. Below you can see simple example:

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.support.SimpleCacheManager;

@Configuration
@EnableCaching
public class CachingConfig
{
   @Bean
   public CacheManager cacheManager()
   {
      SimpleCacheManager cacheManager = new SimpleCacheManager();
      cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("employeeByCode")));
      return cacheManager;
   }
}

To prevent usage of outdated data you should remember about cache eviction.



来源:https://stackoverflow.com/questions/65756768/entity-not-returned-from-l1-cache

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!