Java / Hibernate - операции записи не разрешены в режиме только для чтения - PullRequest
14 голосов
/ 25 июля 2011

В последнее время у меня много раздражающих исключений, и после некоторых исследований в Google и на этом форуме я так и не нашел ответа, который мог бы решить мою проблему.

Вот в чем дело - иногда я получаю следующую ошибку при попытке обновить или создать новый объект в режиме гибернации:

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)

Что действительно странно, так это то, что иногда при обновлении объекта методом getHibernateTemplate().saveOrUpdate(object); он будет работать, но иногда с тем же объектом и при вызове того же метода не работает, но, похоже, это зависит от того, как Я получаю объект в первую очередь.

Пример: допустим, у меня есть таблица с 3 полями: идентификатор, тип, длина. Может случиться так, что, если я получу объект по идентификатору и обновлю длину, он будет работать. Если я получу его по типу и обновлю длину, то он не будет работать. Итак, что я делал до сих пор, чтобы избежать этой проблемы, так это выбрать объект, метод, который не вызывает проблемы позже, но это становится все более и более раздражающим, чтобы попытаться найти способ, который работает.

Кроме того, теперь у меня есть это исключение при попытке создать объект (но не все из них, только на одной конкретной таблице), и я не могу найти способ обойти это. И я попытался добавить @Transactional(readOnly = false) в транзакцию, но это ничего не изменило, и отображение режима означало, что я все равно не был доступен только для чтения.

Есть предложения?

Править 26 июля: вот некоторая конфигурация, связанная с 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>

также, если это может помочь

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

Правка 31 августа: Соответствующий код в моем классе, который расширяет HibernateDaoSupport, для сохранения объектов:

public void createObject(Object persisObj) {
    getHibernateTemplate().save(persisObj);
}

Ответы [ 10 ]

11 голосов
/ 26 июля 2011

Это сообщение об ошибке обычно появляется при использовании Spring OpenSessionInViewFilter и попытке выполнить операции сохранения за пределами транзакции, управляемой Spring. Фильтр устанавливает для сеанса значение FlushMode.NEVER / MANUAL (в зависимости от используемых вами версий Spring и Hibernate - они примерно эквивалентны). Когда механизм транзакции Spring начинает транзакцию, он изменяет режим сброса на «COMMIT». После того, как транзакция завершится, она при необходимости вернет ее в значение НИКОГДА / РУЧНАЯ. Если вы абсолютно уверены , что этого не происходит, то следующим наиболее вероятным виновником является не-поточно-безопасное использование сеанса. Сессия Hibernate должна использоваться только в одном потоке. Если он пересекается между потоками, может произойти всевозможный хаос. Обратите внимание, что объект, загруженный из Hibernate, может содержать ссылку на сеанс, в который он был загружен, и передача объекта между потоками, таким образом, может также вызвать доступ к сеансу из другого потока.

7 голосов
/ 04 августа 2016

добавить

@Transactional

выше вашей функции

6 голосов
/ 05 декабря 2012

Я изменил свойства одного сеанса из фильтра представления. Проблема решена:

  <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>
6 голосов
/ 31 августа 2011

Я тоже наткнулся на это. Мне нужно было изменить режим сброса в OpenSessionInViewFilter Spring на ручной, и внезапно я начал получать это исключение. Я обнаружил, что проблемы возникали в методах, которые не были аннотированы как @Transactional, поэтому я предполагаю, что Spring неявно обрабатывает весь код доступа к данным вне таких методов только для чтения. Аннотирование метода решило проблему.

Другой способ - вызвать метод setCheckWriteOperations для объекта HibernateTemplate.

5 голосов
/ 19 декабря 2015

Используемый ниже компонент для HibernateTemplate в контексте приложения .

<bean id="template" class="org.springframework.orm.hibernate4.HibernateTemplate">  
        <property name="sessionFactory" ref="mysessionFactory"></property>
        <property name="checkWriteOperations" value="false"></property>
        </bean>
3 голосов
/ 19 апреля 2013

Попробуйте использовать это

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

Ошибка должна исчезнуть, поскольку шаблон не проверяет, используете ли вы транзакцию.

2 голосов
/ 22 октября 2016

Вы должны забыть добавить аннотацию @Transactional к вашему классу / методу обслуживания DAO, это будет означать, что ваша операция с базой данных будет обрабатываться управляемой Spring транзакцией.

1 голос
/ 18 мая 2018

1) добавьте @Transactional выше ваших методов работы с базой данных и 2) убедитесь, что у вас есть менеджер транзакций на основе аннотаций

добавьте

выше конфигурации HibernateTransactionManager в файле applicationContext.xml

1 голос
/ 07 февраля 2016

Ниже кусок кода работает для меня.

hibernateTemplate = new HibernateTemplate(sessionFactory);
hibernateTemplate.setCheckWriteOperations(false);
0 голосов
/ 19 марта 2012

У меня была такая же проблема, и после одного дня расследования я заметил следующее заявление

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

Я удалил

mode="aspectj"

и проблема исчезла

...