【发布时间】:2018-08-07 11:19:20
【问题描述】:
我在 Grails 2.5.0 应用程序中遇到了一个奇怪的 Hibernate4 缓存问题,该应用程序用作从遗留系统迁移的数据的平台。迁移涉及数据库记录的直接数据库插入和删除(在测试迁移 SQL 时)。这些操作导致系统中的页面加载错误,因为缓存的数据与数据库的实际状态不同。特定页面加载失败的堆栈跟踪错误表明缺少记录,其 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
}
重新启动并没有导致问题消失,这让我摸不着头脑——即使在 Tomcat 重新启动之间,这种正常的 Hibernate 行为是否也会永久缓存内容?我在这里完全错过了标记吗?我的下一步是在禁用二级缓存的第一个环境中运行应用程序,但我也希望获得社区反馈,我至少在我的理论方面处于正确的轨道上——这似乎很疯狂。任何建议/反馈表示赞赏!
【问题讨论】:
标签: sql-server hibernate grails