缓存evictAll()后,一些缓存的元素不会被删除

时间:2015-05-05 15:50:31

标签: java spring hibernate jpa ehcache

这是一个Spring + JPA + Hibernate + EhCache应用程序。我面临一些缓存问题(或者我假设这是由于缓存配置)。我试图缓存一些对象(它工作正常,我可以在缓存统计中看到)。问题是我想用按钮刷新缓存,例如,我需要直接更新数据库以从外部应用程序更改某些信息。

ExamForm实体类似于:

@Entity
public class ExaminationForm implements Serializable {
private static final long serialVersionUID = -7235473414679474757L;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID", unique = true, nullable = false)
private Long id;

@Column(nullable = false, length = 150)
private String name;

// Duration in minutes
private Integer duration;

//Getters and setters and other stuff... 

当然,还有很多实体,但工作正常,因此在问题中得到了解决。 DAO或多或少像:

@Repository
public class ExaminationFormDao {

@Override
@Cacheable(value = "examinations", key = "#id")
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
public ExaminationForm get(Long id) {
    return super.get(id);
}

@Override
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
public List<EntityClass> getAll() {
    CriteriaQuery<EntityClass> query = getEntityManager().getCriteriaBuilder().createQuery(getEntityClass());
    query.select(query.from(getEntityClass()));
    try {
        return getEntityManager().createQuery(query).getResultList();
    } catch (NoResultException nre) {
        return new ArrayList<EntityClass>();
    }
}

@Caching(evict = { @CacheEvict(value = "examinations", allEntries = true) })
public void evictAllCache() {
    getEntityManager().getEntityManagerFactory().getCache().evictAll();
}

在spring的applicationContext.xml中,我按如下方式定义缓存配置:

<!--  Cache Configuration  -->
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache" />
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:ehcache.xml" p:shared="true" />

Hibernate相关数据仅包含连接信息和C3P0变量。因此我不在这里复制以避免太多代码。

将ehcache.xml配置为:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="usmocache">     
<diskStore path="java.io.tmpdir" />
<defaultCache eternal="true" maxElementsInMemory="0"
    overflowToDisk="false" statistics="true" />
<cache name="examinations" copyOnRead="true" copyOnWrite="true" 
    maxElementsInMemory="2000" eternal="false"
    timeToIdleSeconds="0" timeToLiveSeconds="1200" overflowToDisk="false"
    diskPersistent="false" memoryStoreEvictionPolicy="LFU" statistics="true" />
</ehcache>

还有更多数据,但我不想复制数千行代码来提出这个问题。如果需要,我可以稍后提供更多信息。

检查是否要驱逐所有类我清理该区域,并执行getEntityManager().getEntityManagerFactory().getCache().evictAll();以确保删除。当我按下按钮时,我在两个DAO中调用evictAllCache()。可能不是最好的方法而且是多余的,但我正在尝试不同的方法而没有成功。此外getAll()没有任何@Cacheable注释。

问题是当我访问DAO的getAll方法时。第一次,将Hibernate和缓存调试设置为on,我得到:

SQL [qtp684428083-26] - select examinatio0_.ID as ID1_12_, examinatio0_.duration as duration2_12_, examinatio0_.name as name3_12_ from examination_form examinatio0_
TRACE BasicExtractor [qtp684428083-26] - extracted value ([ID1_12_] : [BIGINT]) - [1]
TRACE BasicExtractor [qtp684428083-26] - extracted value ([duration2_12_] : [INTEGER]) - [15]
TRACE BasicExtractor [qtp684428083-26] - extracted value ([name3_12_] : [VARCHAR]) - [Examination1Name]
TRACE BasicExtractor [qtp684428083-26] - extracted value ([ID1_12_] : [BIGINT]) - [2]
TRACE BasicExtractor [qtp684428083-26] - extracted value ([duration2_12_] : [INTEGER]) - [15]
TRACE BasicExtractor [qtp684428083-26] - extracted value ([name3_12_] : [VARCHAR]) - [Examination2Name]
...

这是预期的行为。在获得所有考试时填写所有考试数据。但是,如果我清理缓存,并再次执行此方法,我只会得到:

SQL [qtp684428083-26] - select examinatio0_.ID as ID1_12_, examinatio0_.duration as duration2_12_, examinatio0_.name as name3_12_ from examination_form examinatio0_
TRACE BasicExtractor [qtp684428083-26] - extracted value ([ID1_12_] : [BIGINT]) - [1]
TRACE BasicExtractor [qtp684428083-26] - extracted value ([ID1_12_] : [BIGINT]) - [2]
...

仅检索ID。在GUI中,我可以看到每个检查的名称和持续时间,意味着信息已经可用,并且休眠不需要再次检索它。因此我假设它被缓存在某个地方。

问题是:

  1. 如何强制再次从数据库重新加载所有这些数据?

  2. 如果DAO中没有注释,为什么getAll()正在使用缓存 方法既不在实体中说它必须是可缓存的。

  3. 我的evictAllCache()方法出了什么问题?

  4. 显然我错了,但我无法找到。

1 个答案:

答案 0 :(得分:2)

您的查询可能是从第一级缓存获取对象。尝试使用getEntityManager().clear();

进行清理