我有一个关于Hibernate缓存机制的问题。我在文章中读到了hibernate中本机SQLquery的执行,使缓存的所有区域无效,因为hibernate对它将影响哪个特定实体一无所知。这里缓存的所有区域意味着我们在讨论二级缓存的各个区域或两个级别的缓存(第一级缓存,第二级缓存)或仅第二级缓存还是仅第一级缓存?
答案 0 :(得分:22)
这个article解释了Hibernate查询缓存的工作原理以及本机查询对现有缓存条目的影响。
使用SQLQuery,Hibernate无法知道您可能会影响哪些缓存区域,但幸运的是,您可以明确地指示它:
SQLQuery sqlQuery = session.createSQLQuery(
"UPDATE CUSTOMER SET ... WHERE ...");
sqlQuery.addSynchronizedEntityClass(Person.class); int
int updateCount = sqlQuery.executeUpdate();
这样它就知道哪些查询缓存无效,否则它可能会丢弃所有内容:
private static class EntityCleanup {
private final EntityRegionAccessStrategy cacheAccess;
private final SoftLock cacheLock;
private EntityCleanup(EntityRegionAccessStrategy cacheAccess) {
this.cacheAccess = cacheAccess;
this.cacheLock = cacheAccess.lockRegion();
cacheAccess.removeAll();
}
private void release() {
cacheAccess.unlockRegion( cacheLock );
}
}
private static class CollectionCleanup {
private final CollectionRegionAccessStrategy cacheAccess;
private final SoftLock cacheLock;
private CollectionCleanup(CollectionRegionAccessStrategy cacheAccess) {
this.cacheAccess = cacheAccess;
this.cacheLock = cacheAccess.lockRegion();
cacheAccess.removeAll();
}
private void release() {
cacheAccess.unlockRegion( cacheLock );
}
}
private class NaturalIdCleanup {
private final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy;
private final SoftLock cacheLock;
public NaturalIdCleanup(NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy) {
this.naturalIdCacheAccessStrategy = naturalIdCacheAccessStrategy;
this.cacheLock = naturalIdCacheAccessStrategy.lockRegion();
naturalIdCacheAccessStrategy.removeAll();
}
private void release() {
naturalIdCacheAccessStrategy.unlockRegion( cacheLock );
}
}
因此,您可以看到该地区的整个数据被逐出。
这仅影响二级缓存。每次运行本机查询时,都不会清除第一级缓存(a.k.a.会话),因为这会分离所有当前"附加实体",从而在实体状态期望中产生意外后果。但是在每个查询(HQL或本机)之前,会话被刷新,因此db和会话在执行查询之前是同步的,因此在发出新的select之前,第一级缓存是一致的。
整个区域将失效,而不是整个二级缓存。实体定义缓存区域,因此更新特定实体表只会删除属于受本机查询影响的特定表的所有实体。
但是重写与本机查询相关联的查询空间定义是一种自定义Hibernate的方法,不像使用默认实现那样清除缓存区域。