春季数据JPA-冬眠的第二层缓存,没有@queryhints

发布于 2025-02-11 06:01:13 字数 1424 浏览 0 评论 0原文

我在春季启动应用程序中使用弹簧数据JPA ,我需要启用 Hibernate的第二级缓存来缓存某些实体。我将Redis用作缓存服务器作为我的应用程序,因此我需要使用 redisson redisson 春季启动集成。这是我的一些启用第二级缓存的代码示例:

@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()方法时,我可以看到Hibernate选择的查询日志。它的意思是 Hibernate不会从我的缓存中加载数据。当我在存储库中覆盖findall()方法时,将@queryhints放在上面时,Hibernate开始从Cache读取!但是我不想覆盖本机弹簧数据方法。换句话说,我想在不使用@queryhints 的情况下使用春季数据默认方法中的Hibernate第二级缓存。有可能吗?

I'm using spring data jpa in my spring boot application and I need to enable hibernate second level cache for caching some entities. I use Redis as cache server for my app and so I need to use Redisson with its spring boot integration. Here is my some code examples for enable second level cache:

@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"

My BaseInfoRepository extends jpa standard CrudRepository. After calling findAll() method for first time, I can see the cache in redis, so putting data into cache is working without problem. But, I can see hibernate select query logs next times when calling findAll() method. It means hibernate does not load data from my cache. When I override the findAll() method in my repository and put @QueryHints on it, hibernate starts to reading from cache! But I don't want to override native spring data methods. In the other words, I want to use hibernate second level cache in spring data default methods without using @QueryHints. Is that possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

﹏半生如梦愿梦如真 2025-02-18 06:01:13

要应用第二级缓存,您需要定义@cachable@cache the Entity的注释。在这些更改之后,方法findbyid保存crudrepository delete将自动使用第二级缓存,而无需其他提示。

但是findallfindallbyid方法是不同的。他们正在使用引擎盖下的JPQL查询来加载记录。如果我们想缓存Findall方法的结果,并避免使用多个查询执行,则需要使用查询缓存。
配置查询缓存后,默认情况下尚无查询。查询需要明确标记为缓存。

根据

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

我们可以简化所有存储库的限制,并避免为每个特定存储库定义提示。我们可以扩展crudrepository并将所有必需的查询标记为可在我们的新扩展querycachecrudrepository

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 crudrepository 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来简化此限制。您不需要覆盖所有特定特定的存储库中的基本方法。

To apply second-level cache you need to define @Cacheable and @Cache annotations for the entity. After these changes methods findById, save, deleteof CrudRepository will use second-level cache automatically without additional hints.

But findAll and findAllById methods are something different. They are using JPQL query under the hood for loading records. If we want to cache results of findAll method and avoid multiple query executions we need to use the query cache.
After configuring the query cache, by default no queries are cached yet. Queries need to be marked as cached explicitly.

According to hibernate documentation.

By default, individual queries are not cached even after enabling
query caching. Each particular query that needs to be cached must be
manually set as cacheable. This way, the query looks for existing
cache results or adds the query results to the cache when being
executed.

We can simplify this restriction for all our repositories and avoid defining hints for each specific repository. We can extend CrudRepository and mark all required queries as cachable one time in our new extended QueryCacheCrudRepository

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);
}

Then use new QueryCacheCrudRepository instead of CrudRepository for our repositories.

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

Example of usage:

    @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
    }

Summary:

Methods that use queries must be marked as cacheable via hint. It is according to documentation. This restriction can be simplified thru an extended CrudRepository. You do not need to override base methods in all entity specific repositories.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文