在我解決完上一個問題以後,立刻又出現了新的問題,錯誤以下: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