Java / Hibernate - Write operations are not allowed in read-only mode
Asked Answered
A

14

17

I've been having an annoying exception a lot lately, and after some research on Google and this forum I still haven't found an answer that could solve my problem.

Here's the thing - sometimes, I get the following error when trying to update or create a new object with hibernate:

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.
at org.springframework.orm.hibernate3.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1186)
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:696)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:419)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:694)

What is really strange is that, sometimes when updating an object with the method getHibernateTemplate().saveOrUpdate(object); it will work, but sometimes with the same object and by calling the same method it doesn't work, but it seems to depend on how I get the object in the first place.

Example: let's say I have a table with 3 fields: id, type, length. What can happen is that, if I get the object by the id and update the length, then it will work. If I get it by the type and update the length, then it won't work. So what I've been doing so far to avoid the problem is to fetch the object the method that does not cause a problem later, but this is becoming more and more annoying to try and find a way that works.

Also, now I have this exception when trying to create an object (but not all of them, just on one specific table), and can't find a way for a workaround. And I tried to add @Transactional(readOnly = false) in the transaction but it didn't change anything, and displaying the mode was saying that I wasn't in read-only anyway.

Any suggestions?

Edit 26th of July: here's some configuration related to hibernate

<property name="hibernateProperties">
    <props>
        <prop key="jdbc.fetch_size">20</prop>
        <prop key="jdbc.batch_size">25</prop>
        <prop key="cglib.use_reflection_optimizer">true</prop>
        <prop key="hibernate.show_sql">true</prop>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
        <prop key="connection.autoReconnect">true</prop>
        <prop key="connection.autoReconnectForPools">true</prop>
        <prop key="connection.is-connection-validation-required">true</prop>
    </props>
</property>

also, if it can help

<property name="transactionAttributes">
    <props>
        <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
        <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
        <prop key="execute*">PROPAGATION_REQUIRED</prop>
        <prop key="add*">PROPAGATION_REQUIRED</prop>
        <prop key="create*">PROPAGATION_REQUIRED</prop>
        <prop key="update*">PROPAGATION_REQUIRED</prop>
        <prop key="delete*">PROPAGATION_REQUIRED</prop>
    </props>
</property>

Edit 31st of August: The relevant code in my Class that extends HibernateDaoSupport, to save the objects is:

public void createObject(Object persisObj) {
    getHibernateTemplate().save(persisObj);
}
Ani answered 24/7, 2011 at 22:22 Comment(2)
Are you using @Cache with READ_ONLY mode? Or have a method/class annotated with @Transactional(readOnly = true) somewhere? I have ran into these sort of issues myself and found that these two configurations play a role on this error. Mostly if you load an object, modify it and persist it again. I am particularly not very fond of using HibernateTemplate, that also may be hiding some configuration in the background. If you past some snippets of your configuration I might be able to help.Aretta
Thanks T Man for taking the time to reply. So I've search for any of @Cache/@Transactional in my whole project, and there was no such thing (and I never put it in my project). I actually didn't configure hibernate or write the methods, but I'll add my configuration in the post now. Also, this error appears when creating some objects, but not all of them (always the same though), so it is not only related to updating an objectAni
D
8

I changed the single session propery from view filter. Problem solved:

  <filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    <init-param>
      <param-name>singleSession</param-name>
      <param-value>false</param-value>
    </init-param>
  </filter>
Dress answered 5/12, 2012 at 15:11 Comment(1)
I tried getHibernateTemplate().getSessionFactory().getCurrentSession().setFlushMode(FlushMode.AUTO); and my problem solved...Murther
F
17

That error message is typically seen when using the Spring OpenSessionInViewFilter and trying to do persistence operations outside of a Spring-managed transaction. The filter sets the session to FlushMode.NEVER/MANUAL (depending on the versions of Spring and Hibernate you're using--they're roughly equivalent). When the Spring transaction mechanism begins a transaction, it changes the flush mode to "COMMIT". After the transaction completes, it sets it back to NEVER/MANUAL, as appropriate. If you're absolutely sure that this isn't happening, then the next most likely culprit is non-thread-safe use of a Session. The Hibernate Session must be used in only one thread. If it crosses over between threads, all kinds of chaos can happen. Note that an entity loaded from Hibernate can hold a reference to the Session in which it was loaded, and handing the entity across threads can thus cause the Session to be accessed from another thread, too.

Footwork answered 26/7, 2011 at 1:4 Comment(4)
Thanks for your answer. You seem to know a lot about this, and I'm a bit confused about your answer. So I'm using Eclipse to develop, what do you reckon I should do to either detect/correct the problem? what could I do to try and fix it?Ani
Best way to start is probably to add an exception breakpoint on the InvalidDataAccessApiUsageException, and then debug the app and make it happen. Then check the stack to see how you got to the exception. Especially check to see how and where the session was opened and whether a transaction was started. You can tell some of it from the exception stacktrace, but having it live in a debugger is better.Footwork
Well I'm still stuck on this. I tried to debug the thing but really don't see what I can do from it. I don't see any session or whatsoever in there. Anybody else has suggestions?Ani
Answer is helpful even after 7 years. I was getting this issue in persisting data and method was not annoted with @transaction i.e was outside spring transaction.Slobber
R
10

add

@Transactional

above your function

Reimpression answered 4/8, 2016 at 10:16 Comment(0)
D
8

I changed the single session propery from view filter. Problem solved:

  <filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    <init-param>
      <param-name>singleSession</param-name>
      <param-value>false</param-value>
    </init-param>
  </filter>
Dress answered 5/12, 2012 at 15:11 Comment(1)
I tried getHibernateTemplate().getSessionFactory().getCurrentSession().setFlushMode(FlushMode.AUTO); and my problem solved...Murther
P
6

I just stumbled onto this too. I needed to change the flush mode in Spring's OpenSessionInViewFilter to manual, and suddenly I started getting this exception. I found out that the problems were happening in methods that were not annotated as @Transactional, so I guess that Spring implicitly treats all data access code outside such methods as read only. Annotating the method solved the problem.

Another way is to call the setCheckWriteOperations method on the HibernateTemplate object.

Peccary answered 31/8, 2011 at 8:25 Comment(2)
so I tried to add @Transactional to the method (see my edit post for the code): did not change anything. Then I tried to call setCheckWriteOperations(false); before the save, got the exception: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed. Then I tried to remove the ,readOnly part of the <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> (see my first edit) and it worked! With this, @Transactional and the check thing don't matter, but I guess this is not a good fix. Any idea why this is happening?Ani
I really don't ave a clue. Your get* properties wouldn't by any chance create some new objects? Say, add an entry into a log database table or something similar?Peccary
B
5

Use below bean for HibernateTemplate in application context.

<bean id="template" class="org.springframework.orm.hibernate4.HibernateTemplate">  
        <property name="sessionFactory" ref="mysessionFactory"></property>
        <property name="checkWriteOperations" value="false"></property>
        </bean>
Bulletproof answered 19/12, 2015 at 12:38 Comment(0)
B
4

Try to use this

hibernateTemplate = new HibernateTemplate(sessionFactory);
hibernateTemplate.setCheckWriteOperations(false);

The error should go away as the template is not checking if you are using a transaction.

Boiler answered 19/4, 2013 at 16:36 Comment(1)
I tried getHibernateTemplate().getSessionFactory().getCurrentSession().setFlushMode(FlushMode.AUTO); and my problem solved.Murther
R
2

Below piece of code is worked for me.

hibernateTemplate = new HibernateTemplate(sessionFactory);
hibernateTemplate.setCheckWriteOperations(false);
Reiterant answered 7/2, 2016 at 15:13 Comment(0)
B
2

You must forgot to add @Transactional annotation to your DAO service class/method, this will specify that your database operation will be handled by spring managed transaction.

Brunt answered 22/10, 2016 at 8:57 Comment(0)
S
2
  1. Add @Transactional above you database operation methods

  2. Make sure you have annotation driven transation manager add <tx:annotation-driven/> above HibernateTransactionManager configuration in applicationContext.xml file

Swot answered 18/5, 2018 at 19:21 Comment(0)
T
1

Add @Transactional annotation on Dao/Repository class

@Repository
@Transactional
public class XxxRepository {
    
    @Autowired
    private HibernateTemplate hibernateTemplate;
    
    .
    .
    .

}
Tsaritsyn answered 25/9, 2021 at 10:57 Comment(1)
Though not sure if it's the best solution, it worked for me.Footstool
G
0

I had the same problem and after one day of investigation I observed the following declaration

<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>

I removed

mode="aspectj"

and the problem disappeared

Guttapercha answered 19/3, 2012 at 17:4 Comment(2)
unfortunately I don't have a tx:annotation-driven tag in any of my config filesAni
Maybe you must put it in your config file because in default way it has some wrong attribute values for your transaction manager. This problem is result of wrong configuration and you must find what's wrongGuttapercha
F
0

Try to use this

this.getHibernateTemplate().setCheckWriteOperations(false);

Still if you are using hibernate4 and not able to update entity/table then you need to create session and need to do flush the session i.e.

this.getHibernateTemplate().setCheckWriteOperations(false);
Session session = this.getHibernateTemplate().getSessionFactory().openSession();
session.saveOrUpdate(entityName,app);
session.flush();
session.close();
Filigree answered 7/4, 2020 at 14:43 Comment(0)
H
0

Kindly paste below in your servlet xml:-

    <tx:annotation-driven />

you are missing it.

Hanhhank answered 15/2, 2022 at 17:0 Comment(1)
Please explain in what point of the .xml file this should go, or even better uploads the whole new .xml explaining what you corrected and whyExtirpate
T
0

What I did to fix this issue was adding the line <property name="checkWriteOperations" value="false"></property> inside the org.springframework.orm.hibernate4.HibernateTemplate bean tag in the config.xml file like this:

<bean id="template" class="org.springframework.orm.hibernate4.HibernateTemplate">  
    <property name="sessionFactory" ref="mysessionFactory"></property>
    <property name="checkWriteOperations" value="false"></property>
</bean>
Trifacial answered 9/6 at 9:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.