出現錯誤: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into

在我解決完上一個問題以後,立刻又出現了新的問題,錯誤以下:html

org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition. at org.springframework.orm.hibernate5.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1080)
    at org.springframework.orm.hibernate5.HibernateTemplate.lambda$save$11(HibernateTemplate.java:635)
    at org.springframework.orm.hibernate5.HibernateTemplate.doExecute(HibernateTemplate.java:381)
    at org.springframework.orm.hibernate5.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:347)
    at org.springframework.orm.hibernate5.HibernateTemplate.save(HibernateTemplate.java:634)
    at com.spring.oa.dao.impl.PersonDaoImpl.savePerson(PersonDaoImpl.java:11)
    at com.spring.oa.service.impl.PersonServiceImpl.savePerson(PersonServiceImpl.java:20)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:338)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:197)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy34.savePerson(Unknown Source)
    at spring.oa.test.PersonTest.testSavePerson(PersonTest.java:14)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

錯誤的緣由說的很清楚:只讀模式下(FlushMode.NEVER/MANUAL)寫操做不被容許:把你的Session改爲FlushMode.COMMIT/AUTO或者清除事務定義中的readOnly標記。java

下面是錯誤代碼:spring

<tx:advice transaction-manager="transactionManager" id="tx">
        <tx:attributes>
            <tx:method name="save*" read-only="true" />
            <tx:method name="update*" read-only="true" />
            <tx:method name="delete*" read-only="true" />
            <tx:method name="*" read-only="true" />
        </tx:attributes>
    </tx:advice>

下面是修正以後的代碼:session

<tx:advice transaction-manager="transactionManager" id="tx">
        <tx:attributes>
            <tx:method name="save*" read-only="false" />
            <tx:method name="update*" read-only="false" />
            <tx:method name="delete*" read-only="false" />
            <tx:method name="*" read-only="true" />
        </tx:attributes>
    </tx:advice>

 

我來解(照)釋(搬)一下原理:eclipse

經過getSession()取回來的session的flush mode 是FlushMode.NEVER,FlushMode.NEVER只支持read-only(),簡而言之就是,只能對數據進行讀的操做,其他的操做不被容許。只有當session的類型爲FlushMode.AUTO時,纔可以進行修改等操做。若是想把session的類型設爲FlushMode.AUTO的話,就須要繼承OpenSessionInViewFilter類,而後重寫這個方法。不過我不是很推薦這個作法。若是你但願這樣作得話,請參閱博客:http://blog.sina.com.cn/s/blog_59bc146c0100emn2.html 。lua

若是須要再詳細一點的瞭解的話,我摘錄一下大牛的解釋:spa

錯誤緣由:
          OpenSessionInViewFilter在getSession的時候,會把獲取回來的session的flush mode 設爲FlushMode.NEVER。而後把該sessionFactory綁定到TransactionSynchronizationManager,使request的整個過程都使用同一個session,在請求事後再接除該sessionFactory的綁定,最後closeSessionIfNecessary根據該session是否已和transaction綁定來決定是否關閉session。在這個過程當中,若HibernateTemplate 發現自當前session有不是readOnly的transaction,就會獲取到FlushMode.AUTO Session,使方法擁有寫權限。也便是,若是有不是readOnly的transaction就能夠由Flush.NEVER轉爲Flush.AUTO,擁有insert,update,delete操做權限,若是沒有transaction,而且沒有另外人爲地設flush model的話,則doFilter的整個過程都是Flush.NEVER。因此受transaction(聲明式的事務)保護的方法有寫權限,沒受保護的則沒有。.net

博客原文地址:http://blog.csdn.net/tfy1332/article/details/8679711hibernate

相關文章
相關標籤/搜索