繁体   English   中英

spring data jpa - 没有@QueryHints的休眠二级缓存

[英]spring data jpa - hibernate second level cache without @QueryHints

我在我的spring boot应用程序中使用spring data jpa ,我需要启用hibernate二级缓存来缓存一些实体。 我使用 Redis 作为我的应用程序的缓存服务器,因此我需要将Redisson与它的 Spring Boot 集成一起使用。 这是我启用二级缓存的一些代码示例:

@Entity
@Cacheable
@Cache(region = "baseInfoCache", usage = CacheConcurrencyStrategy.READ_WRITE)
public class BaseInfo {
}

application.yml

spring:
  jpa:
    properties:
      hibernate:
        cache:
          use_query_cache: true
          use_second_level_cache: true
          use_structured_entries: true
          region_prefix: dd_hibernate
          region:
            factory_class: org.redisson.hibernate.RedissonRegionFactory
          redisson:
            fallback: true
            config: redisson/redisson-dev.yaml

redisson-dev.yml

singleServerConfig:
  address: "redis://localhost:6379"

我的BaseInfoRepository扩展了 jpa 标准CrudRepository 第一次调用findAll()方法后,我可以看到 redis 中的缓存,因此将数据放入缓存中没有问题。 但是,下次调用findAll()方法时,我可以看到休眠选择查询日志。 这意味着休眠不会从我的缓存中加载数据 当我在我的存储库中覆盖findAll()方法并将@QueryHints放在它上面时,休眠开始从缓存中读取! 但我不想覆盖本机弹簧数据方法。 换句话说,我想在 spring 数据默认方法中使用休眠二级缓存而不使用 @QueryHints 那可能吗?

要应用二级缓存,您需要为实体定义@Cacheable@Cache注释。 经过这些更改后, CrudRepositoryfindByIdsavedelete方法将自动使用二级缓存,无需额外提示。

但是findAllfindAllById方法是不同的。 他们在后台使用 JPQL 查询来加载记录。 如果我们想缓存findAll方法的结果并避免多次查询执行,我们需要使用查询缓存。 配置查询缓存后,默认情况下还没有缓存查询。 查询需要显式标记为缓存。
根据休眠文档

默认情况下,即使启用了查询缓存,单个查询也不会被缓存。 每个需要缓存的特定查询必须手动设置为可缓存。 这样,查询会在执行时查找现有的缓存结果或将查询结果添加到缓存中。

我们可以为所有存储库简化此限制,并避免为每个特定存储库定义提示。 我们可以在新扩展的QueryCacheCrudRepository中扩展CrudRepository并将所有需要的查询标记为可缓存一次

import org.springframework.data.jpa.repository.QueryHints;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.NoRepositoryBean;

import javax.annotation.Nonnull;
import javax.persistence.QueryHint;

@NoRepositoryBean
public interface QueryCacheCrudRepository<T, ID> extends CrudRepository<T, ID> {
  @QueryHints({
          @QueryHint(name = "org.hibernate.cacheable", value = "true")
  })
  Iterable<T> findAll();

  @QueryHints({
          @QueryHint(name = "org.hibernate.cacheable", value = "true")
  })
  Iterable<T> findAllById(Iterable<ID> ids);
}

然后为我们的存储库使用新的QueryCacheCrudRepository而不是CrudRepository

public interface BaseInfoRepository extends QueryCacheCrudRepository<BaseInfo, Long{
    BaseInfo findByName(String name);
}

使用示例:

    @Transactional
    public Iterable<BaseInfo> getAllBaseInfo() {
        baseInfoRepository.findAll(); // call DB to load all data and put it to query cache and second-level cahce
        return  baseInfoRepository.findAll(); // DB is not called. Data retrived from the cahce
    }

概括:
使用查询的方法必须通过提示标记为可缓存。 这是根据文档。 这个限制可以通过扩展的CrudRepository来简化。 您不需要覆盖所有实体特定存储库中的基本方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM