Error: write operations are not allowed in read-only mode (flushmode. Never/manual)

Source: Internet
Author: User

In the past few days, I encountered an error:

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.

 

This is because write operations are not allowed in read-only mode (flushmode. Never) is caused by using the open session in view provided by spring)

There are two solutions after the test:

1. Remove

<Filter>
<Filter-Name> hibernatefilter </filter-Name>
<Filter-class>
Org. springframework. Orm. hibernate3.support. opensessioninviewfilter
</Filter-class>
</Filter>

Here is: session management. When using hibernatetemplate to operate the database, you can not display the session, spring can automatically process the opening and closing of the session.

You can also modify it:

<Filter>
<Filter-Name> lazyloadingfilter </filter-Name>
<Filter-class> org. springframework. Orm. hibernate3.support. opensessioninviewfilter </filter-class>

<Init-param>
<Param-Name> singlesession </param-Name>
<Param-value> true </param-value>
<Param-Name> flushmode </param-Name>
<Param-value> auto </param-value>
</Init-param>
</Filter>
If no value exists in the database, the execution is as follows:

This. gethibernatetemplate (). Save (..);
Gethibernatetemplate (). Flush ();

2. Configure in application-context.xml:

<Bean id = "transactionmanager"
Class = "org. springframework. Orm. hibernate3.hibernatetransactionmanager">
<! -- Hibernatetransactionmanager Bean must be referenced by injecting a sessionfactory bean dependency -->
<Property name = "sessionfactory">
<Ref local = "sessionfactory"/>
</Property>
</Bean>
<! -- Configure the transaction interceptor -->
<Bean id = "transactioninterceptor"
Class = "org. springframework. transaction. Interceptor. transactioninterceptor">
<! -- The transaction interceptor bean needs to inject a Transaction Manager dependency -->
<Property name = "transactionmanager" ref = "transactionmanager"/>
<Property name = "transactionattributes">
<! -- The following defines the transaction propagation attribute -->
<Props>
<Prop key = "delete *"> propagation_required </prop>
<Prop key = "*"> propagation_required </prop>
</Props>
</Property>
</Bean>
<! -- Define beannameautoproxycreator. This bean does not need to be referenced, so there is no ID attribute. This bean automatically creates a transaction proxy for the target bean Based on the transaction interceptor -->
<Bean
Class = "org. springframework. AOP. Framework. autoproxy. beannameautoproxycreator">
<! -- Specify which bean names are used to automatically generate a Service proxy -->
<Property name = "beannames">
<! -- The following are all the beans that need to automatically create the transaction proxy -->
<List>
<Value> xsservice </value>
<Value> kcservice </value>
<Value> cjservice </value>
<Value> zyservice </value>
</List>
<! -- Here, you can add other beans that require automatic transaction proxy creation. -->
</Property>
<! -- The following defines the transaction interceptor required by beannameautoproxycreator -->
<Property name = "interceptornames">
<List>
<Value> transactioninterceptor </value>
<! -- Other new interceptor can be added here -->
</List>
</Property>

</Bean>

The reprinted content is as follows:

Many people mentioned an error when using opensessioninview:

 

  1.  

    Org. springframework. Dao. invaliddataaccessapiusageexception: write operations

     

  2.  

    Are not allowed in read-only mode (flushmode. Never)-Turn your session

     

  3.  

    Flushmode. Auto or remove 'readonly' marker from transaction Definition

     

 

Let's look at several methods in opensessioninviewfilter.

 

  1.  

    Protected void dofilterinternal (httpservletrequest request,

    Httpservletresponse response, filterchain)

    Throws servletexception, ioexception {

    Sessionfactory = lookupsessionfactory ();

    Logger. debug ("Opening hibernate session in opensessioninviewfilter ");

    Session session = getsession (sessionfactory );

    Transactionsynchronizationmanager. bindresource (

    Sessionfactory, new sessionholder (Session ));

    Try {

    Filterchain. dofilter (request, response );

    }

    Finally {

    Transactionsynchronizationmanager. unbindresource (sessionfactory );

    Logger. debug ("Closing hibernate session in opensessioninviewfilter ");

    Closesession (Session, sessionfactory );

    }

    }

     

     

  2.  

    Protected session getsession (sessionfactory)

    Throws dataaccessresourcefailureexception {

    Session session = sessionfactoryutils. getsession (sessionfactory, true );

    Session. setflushmode (flushmode. Never );

    Return session;

    }

     

  3.  

    Protected void closesession (session, sessionfactory)

    Throws cleanupfailuredataaccessexception {

    Sessionfactoryutils. closesessionifnecessary (Session, sessionfactory );

    }

 

We can see that opensessioninviewfilter sets the flush mode of the retrieved session to flushmode. Never when getsession. Then, bind the sessionfactory to transactionsynchronizationmanager, so that the entire request process uses the same session. After the request
Sessionfactory binding. Finally, closesessionifnecessary determines whether to close the session based on whether the session has been bound to transaction. In this process, if hibernatetemplate finds that the current session has a transaction that is not readonly, it will get flushmode. Auto session, so that the method has the write permission.

 

  1.  

    Public static void closesessionifnecessary (session, sessionfactory)

     

  2.  

    Throws cleanupfailuredataaccessexception {

     

  3.  

    If (session = NULL |

    Transactionsynchronizationmanager. hasresource (sessionfactory )){

     

  4.  

    Return;

     

  5.  

    }

     

  6.  

    Logger. debug ("Closing hibernate session ");

     

  7.  

    Try {

     

  8.  

    Session. Close ();

     

  9.  

    }

     

  10.  

    Catch (jdbcexception ex ){

     

  11.  

    // Sqlexception underneath

     

  12.  

    Throw new cleanupfailuredataaccessexception ("cocould not close hibernate session", Ex. getsqlexception ());

     

  13.  

    }

     

  14.  

    Catch (hibernateexception ex ){

     

  15.  

    Throw new cleanupfailuredataaccessexception ("cocould not close hibernate session", ex );

     

  16.  

    }

     

  17.  

    }

     

 

That is, if there is a transaction that is not readonly, it can be flush. convert never to flush. auto has the insert, update, and delete permissions. If there is no transaction and there is no other artificially set flush model, the entire process of dofilter is flush. never. Therefore, the method protected by transaction has the write permission, but not the method protected by transaction.

Use the Spring transaction declaration to control the method by transaction.

 

  1.  

    <Bean id = "basetransaction"

    Class = "org. springframework. transaction. Interceptor. transactionproxyfactorybean"

    Abstract = "true">

    <Property name = "transactionmanager" ref = "transactionmanager"/>

    <Property name = "proxytargetclass" value = "true"/>

    <Property name = "transactionattributes">

    <Props>

    <Prop key = "get *"> propagation_required, readonly </prop>

    <Prop key = "find *"> propagation_required, readonly </prop>

    <Prop key = "load *"> propagation_required, readonly </prop>

    <Prop key = "Save *"> propagation_required </prop>

    <Prop key = "add *"> propagation_required </prop>

    <Prop key = "Update *"> propagation_required </prop>

    <Prop key = "Remove *"> propagation_required </prop>

    </Props>

    </Property>

    </Bean>

     

  2. <Bean id = "userservice" parent = "basetransaction">

     

    <Property name = "target">

    <Bean class = "com. phopesoft. Security. Service. impl. userserviceimpl"/>

    </Property>

    </Bean>

 

For the preceding example, The Methods Starting with Save, add, update, and remove have writable transactions. If there is a method, for example, importexcel (), you do not have the write permission because you do not have the transaction permission. If you have insert, update, and delete operations in the method, you need to manually set the flush model to flush. auto, such

 

  1.  

    Session. setflushmode (flushmode. Auto );

     

  2.  

    Session. Save (User );

     

  3.  

    Session. Flush ();

     

 

The open session in view looks good, but it has many side effects. Check the dofilterinternal method code of opensessioninviewfilter. This method is actually called by the dofilter of the parent class. Therefore, we can understand the call process of opensessioninviewfilter: request) -> open session and start transaction-> controller-> View (JSP)-> end transaction and
Close session.

Everything looks correct, especially when there is no problem during local development and testing, but imagine if a step in the process is blocked, in this period, the connection will remain occupied and will not be released. The most likely blocked step is to write JSP. On the one hand, it may be because the page content is large, response. Write takes a long time, and on the other hand, it may be because the network speed is slow and the transmission time between the server and the user is long. When a large number of such cases occur, there will be insufficient connection pool connections, resulting in a false page death.

Open session in view is a double-edged sword. Please use it with caution when the content on the public network is heavy.

 

The following part is taken from: http://zuiyanwangyue.iteye.com/blog/364281

By reading this code, we can easily see that before calling the Save or saveorupdate methods of hibernatetemplate in Java code, we need to set the session refresh mode to flushmode. commit or a higher level, or set the refresh mode of hibernatetemplate to flush_eager. Because our Dao inherits from hibernatedaosupport, the statement for setting the session refresh mode is as follows: getsession (). setflushmode (flushmode. commit );

The statement for setting the hibernatetemplate refresh mode is as follows:

Java code
  1. Hibernatetemplate TMP = gethibernatetemplate ();
  2. TMP. setflushmode (hibernatetemplate. flush_eager );
HibernateTemplate tmp=getHibernateTemplate();   tmp.setFlushMode(HibernateTemplate.FLUSH_EAGER);  

If the hibernatetemplate or session refresh mode is set correctly before calling the hibernatetemplate method involving the write operation, the above exception will not be thrown.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.