首页 文章

当另一个进程修改数据库时,Hibernate二级缓存失效

提问于
浏览
22

我们有一个使用Hibernate的二级缓存来避免数据库命中的应用程序 .

我想知道当一个外部进程如MySQL管理员直接连接修改数据库(更新/插入/删除)时,是否有一些简单的方法可以使Java应用程序的Hibernate二级缓存无效 .

我们使用EHCache作为我们的二级缓存实现 .

我们混合使用@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)和@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE),并且我们没有在每个实体上使用时间戳启用Optimistic并发控制 .

SessionFactory包含管理二级缓存的方法: - Managing the Caches

sessionFactory.evict(Cat.class, catId); //evict a particular Cat
sessionFactory.evict(Cat.class);  //evict all Cats
sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections

但是因为我们使用@Cache注释单个实体类,所以我们没有“可靠”(例如,没有手动步骤)将其添加到列表的中心位置 .

// Easy to forget to update this to properly evict the class
public static final Class[] cachedEntityClasses = {Cat.class, Dog.class, Monkey.class}

public void clear2ndLevelCache() {
  SessionFactory sessionFactory = ...   //Retrieve SessionFactory

   for (Class entityClass : cachedEntityClasses) {
       sessionFactory.evict(entityClass);
   }
}

Hibernate的二级缓存没有真正的方法来知道数据库中的实体发生了变化,除非它查询该实体(缓存正在保护您的实体) . 因此,作为一种解决方案,我们可以简单地调用一些方法来强制二级缓存驱逐一切(再次因为缺乏锁定和并发控制,您可能会因“读取”或更新过时数据而导致进程中的事务风险) .

5 回答

  • 14

    基于ChssPly76's注释这里是一个从二级缓存中驱逐所有实体的方法(我们可以通过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();
            for (String entityName : classesMetadata.keySet()) {
                logger.info("Evicting Entity from 2nd level cache: " + entityName);
                sessionFactory.evictEntity(entityName);
            }
        } catch (Exception e) {
            logger.logp(Level.SEVERE, "SessionController", "evict2ndLevelCache", "Error evicting 2nd level hibernate cache entities: ", e);
        }
    }
    
  • 11

    SessionFactory有很多 evict() 方法正是为此目的:

    sessionFactory.evict(MyEntity.class); // remove all MyEntity instances
    sessionFactory.evict(MyEntity.class, new Long(1)); // remove a particular MyEntity instances
    
  • 8

    hibernate和JPA现在都提供了对底层二级缓存的直接访问:

    sessionFactory.getCache().evict(..);
    entityManager.getCache().evict(..)
    
  • 1

    我正在搜索如何使所有Hibernate缓存无效,我发现这个有用的片段:

    sessionFactory.getCache().evictQueryRegions();
    sessionFactory.getCache().evictDefaultQueryRegion();
    sessionFactory.getCache().evictCollectionRegions();
    sessionFactory.getCache().evictEntityRegions();
    

    希望它对其他人有帮助 .

  • 2

    您可以尝试这样做:

    private EntityManager em;
    
    public void clear2ndLevelHibernateCache() {
        Session s = (Session) em.getDelegate();
        SessionFactory sf = s.getSessionFactory();
    
        sf.getCache().evictQueryRegions();
        sf.getCache().evictDefaultQueryRegion();
        sf.getCache().evictCollectionRegions();
        sf.getCache().evictEntityRegions();
    
        return;
    }
    

    我希望它有所帮助 .

相关问题