shank
shank

Reputation: 1

Spring Cache -- can't to get a list of data

I can't to get list of data through ehcache.

servlet-context:

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

I have an entity of Category:

@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;
}
// ...
}

Then, I try to cache this methods:

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

When adding a category, and then try to bring it to view all categories that have user findByParentId/findall, it returns an empty list

[]

It has something to do that for example I cache the categories, and then take the list of categories, I tried to get the category with ID 11 -- findById, and found:

ru.mrchebik.model.Category@f0b8277

Upvotes: 0

Views: 2093

Answers (1)

Louis Jacomet
Louis Jacomet

Reputation: 14500

Your setup has a number of problems both at Ehcache and Spring levels.

For Ehcache, you should not have a smaller disk size than the heap size. For a while now the tiering model in ehcache means that all entries must be in the disk tier, so you are effectively artificially constraining the heap size to the disk size with this setup.

On the Spring side, you are using a single cache to hold different things, but they will conflict.

  • Your @CachePut will store a single category, mapped to a long key which matches what your @Cacheable on findById does.
  • However, this will conflict with the @Cacheable on findAll which also uses a long as the key but caches a List<Category>. So any collision between userId and categoryId can cause unexpected class cast exceptions in client code - expecting a List getting a Category or the opposite.
  • Finally you have two methods which take two long as parameters but do a different service call while the caching is configured the same. And that service call returns again disjoint types - List<Category> and Category. Which will cause similar issues as in the previous point.

Also, I am under the impression that you expect single entry caching to magically append entries to matching lists. This is not going to happen.

I strongly recommend reviewing your caching needs and better understand what the Spring abstraction offers ... and what it does not.

Upvotes: 2

Related Questions