• 出现错误: 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

  • 相关阅读:
    CSS的display小记
    Oracle PL/SQL中的循环处理(sql for循环)
    Windows下Git服务器搭建及使用过程中的一些问题
    IIS故障问题(Connections_Refused)分析及处理
    [转载]Function.apply and Function.call in JavaScript
    CentOS中文乱码问题的解决方法
    sed之G、H、g、h使用
    Linux命令:chgrp chown chmod
    javascirpt倒计时
    linux:sed高级命令之n、N
  • 原文地址:https://www.cnblogs.com/dengkaien/p/7912909.html
Copyright © 2020-2023  润新知