我有一个关于Hibernate缓存机制的问题。我在文章中已经读到,在hibernate中执行本机SQLquery会使缓存的所有区域无效,因为hibernate不知道它将影响哪个特定实体。在这里,缓存的所有区域都是在讨论二级缓存或二级缓存(一级缓存,二级缓存)或仅二级缓存或仅一级缓存的各个区域吗?
该文章介绍了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 ); } }
因此,如您所见,该区域的所有数据都被驱逐了。
这仅影响二级缓存。每次运行本机查询时,都不会清除第一级缓存(也称为会话),因为这会分离当前的所有“附加实体”,从而给实体状态期望带来意外的后果。但是在每个查询(HQL或本机查询)之前,都会刷新会话,以便在执行查询之前数据库和会话处于同步状态,因此在发出新选择之前,一级缓存是一致的。
整个区域将失效,而不是整个二级缓存失效。实体定义了一个缓存区域,因此更新特定实体表只会删除属于该特定表的所有实体,这些实体受本机查询的影响。
但是,覆盖与本机查询关联的查询空间定义是一种自定义Hibernate的方式,该方式不像使用默认实现那样清除缓存区域。