手动更新数据库后清除 Hibernate 二级缓存

Clear Hibernate 2nd level cache after manually DB update

很快,我有一个实体映射到数据库 (Oracle) 中的视图,启用了二级缓存(只读策略) -- ehcache。

如果我手动更新数据库中的某些列 -- 缓存将不会更新。

我没有找到任何方法来做到这一点。仅当更新将通过 Hibernate 实体完成时。

我可以以某种方式实现此功能吗?

也许作业要监视 table(或查看)?或者也许有一些方法可以通知 Hibernate 关于具体 table.

数据库中的更改

感谢您以后的回答!

您可以使用session.refresh()方法重新加载当前在会话中保存的对象。

阅读object loading for more detail

根据Hibernate JavaDoc,您可以使用org.hibernate.Cache.evictAllRegions() :

evictAllRegions() Evict all data from the cache.

使用 Session 和 SessionFactory:

Session session = sessionFactory.getCurrentSession();

if (session != null) {
    session.clear(); // internal cache clear
}

Cache cache = sessionFactory.getCache();

if (cache != null) {
    cache.evictAllRegions(); // Evict data from all query regions.
}

1) 如果你只需要更新一个实体(如果直接从数据库你将只更新某些实体)而不是整个会话,你可以使用

evictEntityRegion(Class entityClass) Evicts all entity data from the given region (i.e.

2) 如果你有很多实体,可以直接从数据库更新你可以使用这个方法从二级缓存中驱逐所有实体(我们可以通过 JMX 或其他管理工具将这个方法公开给管理员) :

/**
 * Evicts all second level cache hibernate entites. This is generally only
 * needed when an external application modifies the game databaase.
 */
public void evict2ndLevelCache() {
    try {
        Map<String, ClassMetadata> classesMetadata = sessionFactory.getAllClassMetadata();
        Cache cache = sessionFactory.getCache();
        for (String entityName : classesMetadata.keySet()) {
            logger.info("Evicting Entity from 2nd level cache: " + entityName);
            cache.evictEntityRegion(entityName);
        }
    } catch (Exception e) {
        logger.logp(Level.SEVERE, "SessionController", "evict2ndLevelCache", "Error evicting 2nd level hibernate cache entities: ", e);
    }
}

3) 描述了另一种方法here for postgresql+hibernate, I think you can do something similar for Oracle like this

你会在这里找到控制二级缓存的方法:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html#performance-sessioncache

从 JEE 7.0 开始:

myStatelessDaoBean.getSession().evict(MyEntity.class);

使用 debezium 从您的数据库进行异步缓存更新。您可以访问 https://debezium.io/

了解更多信息

此外,这篇文章非常有帮助,因为它提供了直接实现 https://debezium.io/blog/2018/12/05/automating-cache-invalidation-with-change-data-capture/

如前所述,当您从后端手动更新数据库时(不是通过应用程序/休眠会话),缓存不会更新。而您的应用程序对此一无所知。

要将更改告知应用程序,您需要根据情况刷新与实体相关的整个缓存或部分缓存。这可以是两种方式之一:

1- 重新启动应用程序 - 在这种情况下,将使用更新的数据库更改重建缓存。

2- 触发更新 w/o 重新启动应用程序 - 您不需要重新启动应用程序,但您想告诉应用程序当前缓存无效并且它应该刷新了。

  • 您可以通过多种方式将此外部推送给您的应用程序。很少有人 下面列出。

    1. 通过 JMX。
    2. 通过带有已发布URL的servlet来刷新缓存。在数据库中更改表后点击 URL。
    3. 在数据库上实现触发器,调用应用程序上的侦听器。
  • 在执行外部推送/管理任务时,您可以根据需要调用合适的缓存相关方法来使缓存失效/刷新缓存。示例:Session.refresh(), Cache.evictAllRegions(), Cache.evictEntityRegion(entityName) etc 如其他帖子所述。