cache evictAll() 后,一些缓存的元素没有被删除

Some cached elements are not deleted after cache evictAll()

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

ExaminationForm 实体类似于:

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

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

<!--  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 和缓存调试设置为开时,我得到:

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 中我可以看到每次检查的名称和持续时间,这意味着信息已经可用并且 hibernate 不需要再次检索它。因此我假设它缓存在某处。

问题是:

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

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

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

显然我哪里错了,但我找不到哪里。

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

清理它