我们有一个使用Hibernate二级缓存以避免数据库命中的应用程序。
我想知道当外部进程(例如MySQL管理员)直接连接到修改数据库(更新/插入/删除)时,是否有一些简单的方法可以使Java应用程序的Hibernate 2级缓存无效。
我们正在使用EHCache作为我们的第二级缓存实现。
我们将@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)和@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)混合使用,并且没有对每个实体使用时间戳启用乐观并发控制。
SessionFactory包含管理二级缓存的方法:- 管理缓存
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的二级缓存没有真正的方法知道数据库中的某个实体已更改,除非它查询该实体(这是缓存保护了您的实体)。因此,也许作为解决方案,我们可以简单地调用某种方法来强制第二级缓存将所有内容逐出(同样由于缺少锁定和并发控制,您有可能因“读取”或更新陈旧数据而导致进行中的交易)。
根据ChssPly76的评论,这是一种从第二级缓存中逐出所有实体的方法(我们可以通过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); } }