【问题标题】:Spring Cache -- can't to get a list of dataSpring Cache - 无法获取数据列表
【发布时间】:2017-07-11 12:54:07
【问题描述】:

我无法通过 ehcache 获取数据列表。

servlet 上下文:

<cache:annotation-driven />

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
    p:cacheManager-ref="ehcache"/>

<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
      p:configLocation="/WEB-INF/spring/appServlet/ehcache.xml" p:shared="true" />

ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="ehcache.xsd"
     updateCheck="true" monitoring="autodetect" dynamicConfig="true">
<cache name="category"
       maxEntriesLocalHeap="5000"
       maxEntriesLocalDisk="1000"
       eternal="false"
       diskSpoolBufferSizeMB="20"
       timeToIdleSeconds="200"
       timeToLiveSeconds="500"
       memoryStoreEvictionPolicy="LFU"
       transactionalMode="off">
    <persistence strategy="localTempSwap"/>
</cache>

我有一个类别的实体:

@Entity
@Table(name = "categories")
public class Category implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long categoryId;

@Column(nullable = false)
private String name;

private long level;
private long parentId;

@ManyToMany(fetch = FetchType.EAGER, mappedBy = "categories")
private Set<Post> posts;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId")
private User user;

public Category() {
}

public Category(User user, long level, String name, long parentId) {
this.user = user;
this.level = level;
this.name = name;
this.parentId = parentId;
}
// ...
}

然后,我尝试缓存这些方法:

@Service
@Repository
@Transactional
public class CategoryServiceImpl implements CategoryService {
@Resource
private CategoryRepository categoryRepository;

@Override
@CachePut(value = "category", key = "#category.categoryId")
public Category add(Category category) {
    return categoryRepository.saveAndFlush(category);
}

@Override
@Cacheable("category")
public Category findById(long id) {
    return categoryRepository.findOne(id);
}

@Override
@Cacheable("category")
public Category findByParentIdThroughCategoryId(long prntId, long userId) {
    return categoryRepository.findByParentIdThroughCategoryId(prntId, userId);
}

@Override
@Cacheable("category")
public List<Category> findByParentId(long prntId, long userId) {
    return categoryRepository.findByParentId(prntId, userId);
}

@Override
@Cacheable("category")
public List<Category> findAll(long userId) {
    return categoryRepository.findAll(userId);
}

@Override
@CacheEvict("category")
public void remove(long id) {
    categoryRepository.delete(id);
}
}

添加一个分类,然后尝试带它查看所有有用户findByParentId/findall的分类,返回一个空列表

[]

这有关系,例如我缓存类别,然后获取类别列表,我尝试获取 ID 为 11 的类别 -- findById,结果:

ru.mrchebik.model.Category@f0b8277

【问题讨论】:

  • 请先确认categoryRepository.findAll(userId)categoryRepository.findByParentId(prntId, userId) 在直接调用时会返回一些内容。另一个不相关的评论是你的CategoryServiceImpl 类不应该用@Repository 注释,只有你的CategoryRepository 应该。
  • 这些方法是返回值。如果不成功,我不会做缓存。嗯...我总是这样做@Repository 并且所有工作。我已将@Repository 移至CategoryRepository,谢谢。
  • @artemisian 我也尝试这样做:@Cacheable(cacheNames = "category", key = "#userId") 但它没有任何改变
  • 您是否有相同值的 userId 和 categoryId?请将 findAll 的 Cacheable 注解替换为@Cacheable(cacheNames = "category", key = "'findAll-'.concat(#userId"))",然后重试。
  • 抱歉有错别字,应该是@Cacheable(cacheNames = "category", key = "'findAll-'.concat(#userId)"

标签: java spring caching ehcache


【解决方案1】:

您的设置在 Ehcache 和 Spring 级别都存在许多问题。

对于 Ehcache,您的磁盘大小不应小于堆大小。一段时间以来,ehcache 中的分层模型意味着所有条目都必须位于磁盘层中,因此您可以通过此设置有效地人为地将堆大小限制为磁盘大小。

在 Spring 方面,您使用单个缓存来保存不同的东西,但它们会发生冲突。

  • 您的@CachePut 将存储一个类别,映射到与findById 上的@Cacheable 匹配的long 键。
  • 但是,这将与findAll 上的@Cacheable 冲突,后者也使用long 作为键,但缓存了List&lt;Category&gt;。因此,userIdcategoryId 之间的任何冲突都可能导致客户端代码中出现意外的类转换异常 - 期望 List 得到 Category 或相反。
  • 最后,您有两种方法,它们将两个long 作为参数,但在缓存配置相同的情况下执行不同的服务调用。并且该服务调用再次返回不相交的类型 - List&lt;Category&gt;Category。这将导致与上一点类似的问题。

另外,我的印象是,您希望单个条目缓存能够神奇地将条目附加到匹配列表中。这不会发生。

我强烈建议检查您的缓存需求,并更好地了解 Spring 抽象提供什么......以及它没有提供什么。

【讨论】:

  • 谢谢,我删除了一些可缓存的元素,留下了2个:findByParentIdfindAll。所以,我添加了密钥:'findByParrentId-' + #category.parentId + ',' + #category.user.userId"'findAll-' + #category.user.userId。你怎么说,我对ClassCastException: ru.mrchebik.model.Category cannot be cast to java.util.List 有一个例外。你能帮我吗,我该如何解决这个问题?
  • 没有堆栈跟踪,很难说。不过可能需要一个单独的问题。
  • 所以堆栈跟踪实际上是我在原始答案中提到的问题。确保您的更改已应用且缓存已清除。
  • 对不起,我不明白我需要做什么
猜你喜欢
  • 2017-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-03
  • 2012-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多