如何在 Spring Data JPA CRUDRepository 中添加缓存功能

Posted

技术标签:

【中文标题】如何在 Spring Data JPA CRUDRepository 中添加缓存功能【英文标题】:How to add cache feature in Spring Data JPA CRUDRepository 【发布时间】:2012-12-04 13:37:36 【问题描述】:

我想在 findOne 方法中添加“Cacheable”注解,并在 delete 或发生方法发生时驱逐缓存。

我该怎么做?

【问题讨论】:

【参考方案1】:

virsir,如果您使用 Spring Data JPA(仅使用接口),还有另一种方法。这是我所做的,用于类似结构化实体的通用 dao:

public interface CachingDao<T, ID extends Serializable> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> 

@Cacheable(value = "myCache")
T findOne(ID id);

@Cacheable(value = "myCache")
List<T> findAll();

@Cacheable(value = "myCache")
Page<T> findAll(Pageable pageable);

....

@CacheEvict(value = "myCache", allEntries = true)
<S extends T> S save(S entity);

....

@CacheEvict(value = "myCache", allEntries = true)
void delete(ID id);

【讨论】:

你能解释一下为什么你使用@CacheEvict作为方法save吗?为什么不使用@CachePut?不会保存它正确更新缓存,因此不需要@Cacheable 在保存后运行(假设缓存仍然存在) @seven 不错!请注意,可以使用@CacheConfig 注释Repo,因此cache 名称将在CachingDao 之外 以@delver 的评论为基础:“Spring 建议您仅使用 @Cache* 注释来注释具体类(和具体类的方法),而不是注释接口。”更多细节见源代码——docs.spring.io/spring/docs/current/spring-framework-reference/… 奇怪的是 Spring 自己的示例显示在接口上使用 @Cache* 注释 ...github.com/spring-projects/spring-data-examples/blob/master/jpa/… 有谁知道为什么在保存或删除单个记录时要逐出所有条目?【参考方案2】:

我认为@seven 的回答基本上是正确的,但缺少 2 点:

    我们不能定义一个通用接口,恐怕我们必须单独声明每个具体接口,因为注释不能被继承,我们需要为每个存储库有不同的缓存名称。

    savedelete 应该是 CachePutfindAll 应该同时是 CacheableCacheEvict

    public interface CacheRepository extends CrudRepository<T, String> 
    
        @Cacheable("cacheName")
        T findOne(String name);
    
        @Cacheable("cacheName")
        @CacheEvict(value = "cacheName", allEntries = true)
        Iterable<T> findAll();
    
        @Override
        @CachePut("cacheName")
        T save(T entity);
    
        @Override
        @CacheEvict("cacheName")
        void delete(String name);
    
    

Reference

【讨论】:

我不知道为什么会有负面评价,但是 1) 是真的,我猜 evic allentries 是因为你的缓存可能有不同的键值然后 PK,因此在修改记录时,你应该指定驱逐什么 - 如果你只有 PK,你不知道缓存键,所以你不知道哪个缓存记录无效【参考方案3】:

我通过以下方式解决了这个问题,并且工作正常


public interface BookRepositoryCustom 

    Book findOne(Long id);



public class BookRepositoryImpl extends SimpleJpaRepository<Book,Long> implements BookRepositoryCustom 

    @Inject
    public BookRepositoryImpl(EntityManager entityManager) 
        super(Book.class, entityManager);
    

    @Cacheable(value = "books", key = "#id")
    public Book findOne(Long id) 
        return super.findOne(id);
    



public interface BookRepository extends JpaRepository<Book,Long>, BookRepositoryCustom 


【讨论】:

我有很多存储库,有没有简单的方法来实现这个? 我不知道其他方式。我只知道这样。【参考方案4】:

尝试提供 MyCRUDRepository(一个接口和一个实现),如下所述:Adding custom behaviour to all repositories。然后您可以覆盖并为这些方法添加注释:

findOne(ID id)
delete(T entity)
delete(Iterable<? extends T> entities)
deleteAll() 
delete(ID id) 

【讨论】:

以上是关于如何在 Spring Data JPA CRUDRepository 中添加缓存功能的主要内容,如果未能解决你的问题,请参考以下文章

处理 JPA 规范和 spring-data-jpa 时如何使用声明 Stream 作为返回类型

使用 spring-data-jpa 获取这些数据如何更正确?

如何在 Spring Data 中漂亮地更新 JPA 实体?

如何禁用嵌入式数据库 Spring-boot spring-data-jpa

从控制台应用程序使用带有休眠功能的spring-data-jpa时如何延迟加载收集

如何在启动时验证 Spring Data JPA 查询?