Hibernate的本地查询和缓存机制

12

我有一个关于Hibernate缓存机制的问题。我在文章中读到,当Hibernate执行本地SQL查询时,会使所有缓存区域失效,因为Hibernate不知道它将影响哪个特定实体。这里提到的所有缓存区域是指第二级缓存的各个区域,还是指两级缓存(一级缓存、二级缓存)的所有区域,或者只是指第二级缓存或仅指一级缓存?


1
只是一句话,执行带有UPDATE语句的本地查询将使所有二级缓存区域失效。如果您执行Insert或Delete本地查询,则缓存不会失效。如果我错了,请纠正我。 - edward_wong
1个回答

29

当使用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 );
    }
}

因此,正如您所看到的,Region的所有数据都被逐出了。

这只影响了二级缓存。每次运行本机查询时,不会清除一级缓存(也称为Session),因为这将分离所有当前的“已附加实体”,导致实体状态期望产生意外后果。但在每个查询(HQL或本机)之前,会刷新会话以使数据库和会话同步,因此在发出新的select之前,第一级缓存是一致的。

整个区域将被无效化,而不是整个二级缓存。实体定义了一个缓存区域,因此更新特定实体表仅会删除受本机查询影响的那些特定表中属于该特定表的所有实体。

但是,覆盖与本机查询相关联的查询空间定义是一种自定义Hibernate的方法,以便不清除缓存区域,就像使用默认实现一样。


那么它只会使第二级缓存失效?但是第一级缓存呢,它不会使其失效吗?据我所知,这个特定的函数告诉Hibernate要使哪个特定的实体失效,而不是使整个缓存失效。 - Beast
1
当您运行任何查询时,第一级缓存会被清除。Hibernate具有未决更改,任何查询都必须转到DB,因此需要刷新未决查询,以便查询返回一致的结果。 - Vlad Mihalcea
会话有时在查询执行之前被刷新,以确保查询永远不会返回过期状态。我认为这很聪明。 - Vlad Mihalcea
弗拉德,Hibernate 4.x是否也会在每个带有更新语句的本地查询中清除第二级缓存?还是这个问题只存在于Hibernate 3.x中? - Johnny
听起来更像是一个问题,而不是对答案的评论。 - Vlad Mihalcea
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接