我们有一个在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配置(仅显示相关部分):
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="datasourceName" />
</property>
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<bean id="hibernateInterceptor"
class="org.springframework.orm.hibernate3.HibernateInterceptor">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<tx:advice id="txAdvice" transaction-manager="txManager" >
<!-- the transactional semantics... -->
<tx:attributes >
<!-- all methods starting with 'get' are read-only -->
<tx:method name="approve*" read-only="false"
propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="update*" read-only="false"
propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="save*" read-only="false"
propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="delete*" read-only="false"
propagation="REQUIRED" rollback-for="java.lang.Exception" />
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" read-only="true" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceMethods"
expression="execution(* com.myapplication.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="serviceMethods" />
</aop:config>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" >
<property name="sessionFactory" ref="sessionFactory" />
</bean>
-- end of spring config --
-- hibernate configuation --
<hibernate-configuration>
<session-factory name="">
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property name="show_sql">false</property>
<property name="use_outer_join">false</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.connection.SetBigStringTryClob">true</property>
<property name="hibernate.jdbc.batch_size">0</property>
</session-factory>
<mapping ----/>
</hibernate-configuration>
这是堆栈跟踪:
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)
一切正常
答案 0 :(得分:2)
此异常来自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.");
}
}
此检查的基本原理为explained:
这是一项新的一致性检查 在Spring 1.1中引入。
调用HibernateTemplate 保存/更新/删除方法 春季管理的会议 FlushMode.NEVER是潜在的 危险:这意味着你是:
要么在Spring管理中执行此操作 只读事务,将会 从不刷新Hibernate Session, 即从不冲洗你的 保存/更新/删除呼叫。新的 检查让你意识到你不会 坚持你的变化 情况。
或与其他人合作 线程中的会话 FlushMode.NEVER,例如 的OpenSessionInViewFilter。如果你是 覆盖closeSession那里冲洗 在视图渲染之后,你应该 覆盖getSession,设置 会话到FlushMode.AUTO。
我强烈地说 但是,建议不要使用后者。 如果你正在使用 OpenSessionInViewFilter,将它组合起来 与中间层交易相反 比过滤器请求刷新 完成。
这有什么响铃?
您的代码或Spring ORM中可能存在一些错误。要禁用此检查,您可以致电setCheckWriteOperations(false)
。
答案 1 :(得分:2)
aseesing,我检查你的配置。在spring context部分,你使用
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" read-only="true" propagation="REQUIRED" />
通常,只有一些访问是只读类型,例如get / find / query等。我建议使用
<!--default is required transaction-->
<tx:method name="*"/>
另一件事是,你使用opensessioninview模式吗?刷新模式可以在opensessioninview中正确设置。您可以在web.xml中使用过滤器,或者在应用程序上下文配置中使用spring拦截器。
答案 2 :(得分:2)
:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>flushMode</param-name>
<param-value>AUTO</param-value>
</init-param>
</filter>
答案 3 :(得分:1)
我的猜测是,Spring会为你做这件事。我似乎记得这是由Spring中的OpenSessionInViewFilter完成的。你在用它吗?
答案 4 :(得分:1)
这是来自记忆所以它不是很详细。有两种设置flushmode的方法。我认为是Spring方式和Hibernate方式。因为我们只使用(Spring?)方式一次,而Hibernate方式所有其他时间都以某种方式使Hibernate的内部状态错误。这造成了我的问题。当我们使一切都保持一致时,问题就消失了。
答案 5 :(得分:1)
我在1个bean中使用了2个“baseTransactionProxy”时遇到了这个:
第一:
<bean id="generalDao" parent="baseTransactionProxy">
<property name="target">
<bean class="com...GeneralDao" parent="baseDAO" />
</property>
</bean>
第二:
<bean id="ruleDao" parent="baseTransactionProxy">
<property name="target">
<bean class="com...RuleDao" parent="baseDAO">
<constructor-arg ref="generalDao"></constructor-arg>
</bean>
</property>
</bean>
我们做了
class ruleDao{
generalDao.generalSaveOrUpdateAll(hbms); // OK HERE
saveOrUpdateAll(otherHbms); //Exception here
}
不确定它是否有帮助,但似乎在同一代理呼叫中混合2个不同的“baseTransactionProxy”并不好...
答案 6 :(得分:0)
因为您在实现上使用执行切入点并且您正在使用通用DAO,所以这可能不会像您期望的那样处理事务,这只是真实问题的一种表现。
请确保Spring按照您的电话预期代理您的DAO。您可能需要使用target(beanid)
语法为通用DAO启用正确的事务。