出現錯誤: 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


在我解決完上一個問題之后,馬上又出現了新的問題,錯誤如下:

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標記。

下面是錯誤代碼:

<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>

下面是修正之后的代碼:

<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>

 

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

通過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 。

如果需要再詳細一點的了解的話,我摘錄一下大牛的解釋:

錯誤原因:
          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(聲明式的事務)保護的方法有寫權限,沒受保護的則沒有。

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM