【发布时间】:2020-11-16 23:59:30
【问题描述】:
我在我的大部分 spring-data 存储库中使用 springs @Cacheable 注释。这包括findById(...) 方法。结果,每次我想编辑和保存实体时,我都会得到一个异常:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
这是我的存储库:
public interface ProductRepository extends Repository<Product, Long> {
@Cacheable(cacheNames = "products", key = "#id")
Optional<Product> findById(Long id);
@Caching(
put = {
@CachePut(cacheNames = "products", key = "#result.id"),
@CachePut(cacheNames = "productByIsbn", key = "#entity.isbn", condition = "#entity.isbn != null")
})
<S extends Product> S save(S entity);
@Override
@Caching(evict = {
@CacheEvict(cacheNames = "products", key = "#entity.id"),
@CacheEvict(cacheNames = "productByIsbn", key = "#entity.isbn", condition = "#entity.isbn != null")
})
void delete(AbstractProductEntity entity);
@Cacheable(cacheNames = "productByIsbn", condition = "#isbn != null")
Optional<Product> findOneByIsbn(String isbn);
}
据我了解,我的缓存实体已与持久化上下文分离,无法再次保存。
解决这个问题的最佳方法是什么?
我知道我可以添加第二个 findByUncached 方法,该方法仅在内部使用并绕过缓存。但在我看来,这似乎是一个糟糕的解决方案,因为我必须对代码段中使用的所有方法都这样做,在这些方法中,实体从存储库中读取并随后再次持久化。
如果我相信我的缓存是最新的,我可以重新附加缓存的对象,但是我如何使用 spring-data 来做到这一点?普通仓库接口上没有合并方法。
EDIT1:感谢 Jens Schauder 指出我的版本问题。
结果是所有缓存实体中的版本属性在调用 save(...) 后没有在缓存中正确更新。虽然我不完全确定为什么会这样,但是用@CacheEvict 替换@CachePut 注释并将缓存更新留给下一次读取解决了这个问题。我现在正在研究 @CachePut 的工作方式。
【问题讨论】:
标签: spring spring-data-jpa spring-data spring-cache