Spring和Hibernate突然将事务设置为readonly
我们有一个在JBoss 4.2.3上运行的应用程序,使用Spring 2.5.2和Hibernate 3.2.6.ga. 这是在Linux JEE01 2.6.16.60-0.54.5-smp上运行,使用自己的用户。 在另一台机器上写入Oracle 10G数据库。
我们使用标准视图 – >服务 – > dao分层。 每个dao都用@Repository注释。
这一切都是全天候运行而没有太多问题,但是每隔几天,有时几天,整个系统都会进入一个糟糕的状态,再也无法将任何内容写入数据库。 这些堆栈跟踪显示在日志中:
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
我们扫描了整个系统,系统中有一个位置,其中flushmode临时设置为MANUAL,之后finally块将其设置回原始值。 这是因为我们不希望在运行此查询之前将状态刷新到数据库。 所以我们不能轻易改变这一点。 普通的FlushMode设置为AUTO,在几个地方我们暂时将其设置为COMMIT并再次将其切换回默认值。
只有服务器重新启动才能将系统恢复到正常工作状态。
问题是:为什么系统将所有事务设置为只读/手动刷新模式? 我用Google搜索了但无法找到解决方案。
这是我们的spring和hibernate配置(仅显示相关部分):
classpath:hibernate.cfg.xml -- end of spring config -- -- hibernate configuation -- org.hibernate.dialect.Oracle10gDialect false false true true org.hibernate.cache.EhCacheProvider true 0
这是堆栈跟踪:
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition. at org.springframework.orm.hibernate3.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1137) at org.springframework.orm.hibernate3.HibernateTemplate$16.doInHibernate(HibernateTemplate.java:701) at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:374) at org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:699) at nl.company.myapp.dao.impl.GenericDAOImpl.save(GenericDAOImpl.java:94) at nl.company.myapp.dao.impl.CallDAOImpl.save(CallDAOImpl.java:266) at nl.company.myapp.dao.impl.CallDAOImpl.save(CallDAOImpl.java:47) at nl.company.myapp.service.impl.CallServiceImpl.saveCall(CallServiceImpl.java:98) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:592) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) at $Proxy142.saveCall(Unknown Source) at nl.company.myapp.view.bean.call.CallDetailBean.doSave(CallDetailBean.java:319) at nl.company.myapp.view.bean.EditModeAwareBean.save(EditModeAwareBean.java:151) at sun.reflect.GeneratedMethodAccessor472.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:592) at org.apache.el.parser.AstValue.invoke(AstValue.java:131) at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276) at com.sun.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:68) at org.apache.myfaces.trinidad.component.MethodExpressionMethodBinding.invoke(MethodExpressionMethodBinding.java:46) at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) at org.apache.myfaces.trinidad.component.UIXCommand.broadcast(UIXCommand.java:190) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:458) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:763) at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:265) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at nl.company.myapp.view.audit.AuditFilter.doFilter(AuditFilter.java:88) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl._invokeDoFilter(TrinidadFilterImpl.java:238) at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl._doFilterImpl(TrinidadFilterImpl.java:195) at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl.doFilter(TrinidadFilterImpl.java:138) at org.apache.myfaces.trinidad.webapp.TrinidadFilter.doFilter(TrinidadFilter.java:92) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:265) at org.acegisecurity.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:107) at org.acegisecurity.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:72) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275) at org.acegisecurity.ui.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:124) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275) at org.acegisecurity.providers.anonymous.AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:125) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275) at org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:81) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275) at org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:271) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275) at org.acegisecurity.ui.logout.LogoutFilter.doFilter(LogoutFilter.java:110) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275) at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275) at org.acegisecurity.util.FilterChainProxy.doFilter(FilterChainProxy.java:149) at org.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:98) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175) at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:182) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:432) at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262) at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:437) at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:366) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446) at java.lang.Thread.run(Thread.java:595)
一切正常
此exception来自Spring的HibernateTemplate类中的以下代码:
protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException { if (isCheckWriteOperations() && getFlushMode() != FLUSH_EAGER && session.getFlushMode().lessThan(FlushMode.COMMIT)) { throw new InvalidDataAccessApiUsageException( "Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): "+ "Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition."); } }
此检查的基本原理解释如下:
这是Spring 1.1中引入的新一致性检查。
在FlushMode.NEVER中的Spring管理的会话上调用HibernateTemplate的保存/更新/删除方法是有潜在危险的:这意味着您:
或者在Spring管理的只读事务中执行此操作,该事务永远不会刷新Hibernate会话,即永远不会刷新您的保存/更新/删除调用。 新检查会让您意识到在这种情况下您不会保留更改。
或者使用FlushMode.NEVER中的其他线程绑定Session,例如OpenSessionInViewFilter。 如果你在视图渲染后重写了closeSession,那么你应该覆盖getSession,将Session设置为FlushMode.AUTO。
不过,我强烈建议不要使用后者。 如果您正在使用OpenSessionInViewFilter,请将其与中间层事务相结合,而不是在请求完成时让filter刷新。
这有什么响铃?
您的代码或Spring ORM中可能存在一些错误。 要禁用此检查,您可以调用setCheckWriteOperations(false)
。
aseesing,我检查你的配置。 在spring的上下文部分,你使用
通常,只有一些访问是只读类型,例如get / find / query等。我建议使用
另一件事是,你使用opensessioninview模式吗? 刷新模式可以在opensessioninview中正确设置。 您可以在web.xml中使用filter或在应用程序上下文配置中使用spring拦截器。
在你的web.xml中放:
openSessionInViewFilter org.springframework.orm.hibernate3.support.OpenSessionInViewFilter flushMode AUTO
我的猜测是Spring会为你做这件事。 我似乎记得这是由Spring中的OpenSessionInViewFilter完成的。 你在用它吗?
这是来自记忆所以它不是很详细。 有两种设置flushmode的方法。 我认为是Spring方式和Hibernate方式。 因为我们只使用(Spring?)方式一次,而Hibernate方式所有其他时间都以某种方式使Hibernate的内部状态错误。 这造成了我的问题。 当我们使一切都保持一致时,问题就消失了。
当从1个bean使用2个“baseTransactionProxy”时我遇到了这个:
第一:
第二:
我们做到了
class ruleDao{ generalDao.generalSaveOrUpdateAll(hbms); // OK HERE saveOrUpdateAll(otherHbms); //Exception here }
不确定它是否有帮助,但似乎在同一个代理调用中混合2个不同的“baseTransactionProxy”并不好……
因为您在实现上使用执行切入点并且您正在使用通用DAO,所以这可能不像您期望的那样处理事务,这只是真实问题的表现。
请确保Spring按照您的电话预期代理您的DAO。 您可能需要使用target(beanid)
语法为通用DAO启用正确的事务。
- Spring / Hibernate测试:在DDL创建后插入测试数据
- Spring 3..0.5 + hierbnate 3.6.6.final + jboss as 7数据库访问
- 如何强制初始化Hibernate JPA代理以在JSON调用中使用它
- 使用更新Cascade进行hibernate软删除
- 相当于Grails中的InheritanceType.TABLE_PER_CLASS?
- JPA 2.0 Hibernate @OneToMany + @MapKeyJoinColumn
- Hibernate比sql查询慢1000倍
- 提高了PostgreSQL查询性能,并且已经连接了1亿个数据
- HibernateException:当’hibernate.dialect’未设置时,对DialectResolutionInfo的访问不能为null