当实体发生改变时Hibernate是通知默认查询缓存失效的机制

我们知道hibernate中除了一级缓存(Session)和二级缓存(SessionFactory)外,还有查询缓存的概念,默认情况下如果未指定region名称,使用Criteria或HQL查询的结果都是存放在默认的查询缓存(指SessionFactoryImpl.getQueryCache())中,那么当相关实体数据更新(增删改)时,hibernate是如何通知默认查询缓存的呢?答案是通过时间戳机制标识实体的最新时间戳,则先前缓存的此实体相关的所有查询结果自动失效(因为此前查询的缓存结果时间戳较早)。

先来看下hibernate是如何标识实体的最新时间戳的。

(1)事务提交时Session的flush方法会通知所有FlushEventListener,见下图:

FlushEventListener[] flushEventListener = listeners.getFlushEventListeners();
for ( int i = 0; i < flushEventListener.length; i++ ) {
    flushEventListener[i].onFlush( new FlushEvent(this) );
}

(2)hibernate的默认刷新事件监听器org.hibernate.event.def.DefaultFlushEventListener是一定被注册的(我们也可以注册自己的监听器),它会调用自己的performExecutions方法,此方法负责执行所有的SQL语句以及二级缓存的更新;

(3)org.hibernate.event.def.DefaultFlushEventListener.performExecutions调用session.getActionQueue().executeActions();

(4)ActionQueue.executeActions()按序执行插入、更新等操作(Executable的具体实例),见下图:

public void executeActions() throws HibernateException {
    executeActions( insertions );
    executeActions( updates );
    executeActions( collectionRemovals );
    executeActions( collectionUpdates );
    executeActions( collectionCreations );
    executeActions( deletions );
}

 (5)调用ActionQueue.execute(Executable),以更新为例,ActionQueue.execute(EntityUpdateAction)

(6)ActionQueue.execute(Executable)方法会调用ActionQueue.registerCleanupActions(Executable)

(7)ActionQueue.registerCleanupActions(Executable)方法中会更新相关实体的时间戳,见下图:

private void registerCleanupActions(Executable executable) {
    beforeTransactionProcesses.register( executable.getBeforeTransactionCompletionProcess() );
    if ( session.getFactory().getSettings().isQueryCacheEnabled() ) {
        final String[] spaces = (String[]) executable.getPropertySpaces();
        afterTransactionProcesses.addSpacesToInvalidate( spaces );
        session.getFactory().getUpdateTimestampsCache().preinvalidate( spaces );
    }
    afterTransactionProcesses.register( executable.getAfterTransactionCompletionProcess() );
}

(8)实体的时间戳更新后先前缓存的查询结果会自动过期,导致不能命中,只能重新查询后再次缓存。

关于查询判断缓存结果是否过期请见StandardQueryCache.get(QueryKey key,Type[] returnTypes,boolean isNaturalKeyLookup,Set spaces,SessionImplementor session)方法和StandardQueryCache.isUpToDate(Set spaces, Long timestamp)方法。

 

土豪请注意: 如果您觉得此文有帮助,可以给支付宝账户zuiyanwangyue@126.com转账进行打赏(可扫描右侧二维码),您的捐助将被用于完善此网站的功能和内容。
加入我们团队: 如果你是技术控并且愿意分享自己掌握的知识,欢迎加入我们团队,请联系QQ:421712311 如本文未能解决您面临的问题,也欢迎随时和我联系以便进一步探讨。

评论列表[0]