我在Grails 2.5.0应用程序中遇到了Hibernate4缓存的一个奇怪问题,该应用程序用作从遗留系统迁移的数据的平台。迁移涉及数据库记录的直接数据库插入和删除(在测试迁移SQL时)。这些操作导致系统中出现页面加载错误,因为缓存数据与数据库的实际状态不同。特定失败页面加载上的Stacktrace错误表示缺少记录,其ID当前未通过外键引用数据库中的任何内容。例如,一个页面无法呈现,并显示以下错误:
018-02-27 10:16:32,495 http-bio-8080-exec-8 | ERROR StackTrace | superAdmin | Full Stack Trace:
org.hibernate.UnresolvableObjectException: No row with the given identifier exists: [com.tlc.worx.company.CompanyQuestion#48466]
at org.hibernate.UnresolvableObjectException.throwIfNull(UnresolvableObjectException.java:68)
at org.hibernate.event.internal.DefaultRefreshEventListener.onRefresh(DefaultRefreshEventListener.java:179)
at org.hibernate.event.internal.DefaultRefreshEventListener.onRefresh(DefaultRefreshEventListener.java:61)
at org.hibernate.internal.SessionImpl.fireRefresh(SessionImpl.java:1121)
at org.hibernate.internal.SessionImpl.refresh(SessionImpl.java:1094)
at org.hibernate.internal.SessionImpl.refresh(SessionImpl.java:1089)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate$10.doInHibernate(GrailsHibernateTemplate.java:342)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:188)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.refresh(GrailsHibernateTemplate.java:339)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.refresh(GrailsHibernateTemplate.java:335)
at org.codehaus.groovy.grails.orm.hibernate.HibernateGormInstanceApi.refresh(HibernateGormInstanceApi.groovy:150)
at com.tlc.worx.company.CompanyQuestion.refresh(CompanyQuestion.groovy)
at com.tlc.worx.company.CompanyQuestion$refresh.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:110)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:114)
at com.tlc.worx.checklist.CompanyQuestionController$_index_closure1$_closure2$_closure3.doCall(CompanyQuestionController.groovy:49)
at com.tlc.worx.checklist.CompanyQuestionController$_index_closure1$_closure2$_closure3.doCall(CompanyQuestionController.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
--
在数据库中搜索被引用的记录号,仅在完全不相关的字段和Tally表中显示它:
(请注意,遇到错误的页面与丢失的记录本身无关,只有一个可能与CompanyQuestion相关但当前与其无关的对象。)
我怀疑Hibernate缓存问题,特别是因为这与删除记录同时发生。此外,将相同的数据库迁移到另一个环境进行测试不会在新环境中产生相同的错误 - 证实了我的理论,即这与环境特定的缓存有关。但奇怪的是,原始环境中的Tomcat7重启(应用程序在Tomcat上运行)不会导致问题消失。 Hibernate配置如下:
hibernate {
cache.use_second_level_cache = true
cache.use_query_cache = false
cache.region.factory_class = 'org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory' // Hibernate 4
singleSession = true // configure OSIV singleSession mode
flush.mode = 'auto' // pre-Hibernate4 default behavior was auto, so we'll stick with that for now. See https://grails.org/2.4.3+Release+Notes
}
重新启动不会导致问题消失让我摸不着头脑 - 这是正常的Hibernate行为,即使在Tomcat重新启动之间也能永久缓存内容吗?我在这里完全错过了这个标记吗?我的下一步是在第一个环境中运行应用程序,禁用第二级缓存,但我想获得社区反馈,我至少在关于我的理论的正确轨道上 - 这看起来很疯狂。任何建议/反馈都赞赏!
答案 0 :(得分:0)
我最终发现这个问题时想要关闭它。
我们的应用程序利用ElasticSearch编译一组数据来查询搜索。我们总是在应用程序重新启动时重新编译ElasticSearch,而不是之前遇到过这个问题,但是我了解到reindex操作并不总是完全按照我们想要的方式执行,并且实际上可以将旧数据作为新记录索引,导致重复或者重复混合包的好/坏记录。
我的问题中的错误是在点击之前的reindex中的一个“坏”的陈旧记录时发生的。在重建索引之前清除所有ElasticSearch索引解决了该问题。