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

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

вот что-иногда я получаю следующую ошибку при попытке обновить или создать новый объект с помощью 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.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 полями: id, type, length. Что может случиться, если я получу объект по идентификатору и обновлю длину, то он будет работать. Если я получу его по типу и обновлю длину, то он не будет работать. Так что я делал до сих пор, чтобы избежать проблемы, чтобы получить объект метод, который не вызывает проблемы позже, но это становится все больше и больше больше раздражает пытаться найти способ, который работает.

кроме того, теперь у меня есть это исключение при попытке создать объект (но не все из них, только на одной конкретной таблице), и не могу найти способ обхода. И я попытался добавить @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 ответов


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

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

это сообщение об ошибке обычно отображается при использовании Spring OpenSessionInViewFilter и пытается выполнять операции сохранения вне транзакции, управляемой весной. Фильтр устанавливает сеанс в FlushMode.Никогда / вручную (в зависимости от версий Spring и Hibernate вы используете-они примерно эквивалентны). Когда механизм транзакции Spring начинает транзакцию, он изменяет режим flush на "COMMIT". После завершения транзакции она возвращает значение Никогда / вручную, в зависимости от обстоятельств. Если ты абсолютно точно что этого не происходит, то следующим наиболее вероятным виновником является не потокобезопасное использование сеанса. Сеанс Hibernate должен использоваться только в одном потоке. Если он пересекается между нитями, может произойти хаос. Обратите внимание, что объект, загруженный из спящего режима, может содержать ссылку на сеанс, в котором он был загружен, и передача объекта по потокам может вызвать доступ к сеансу из другого потока, тоже.


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

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


добавить

@Transactional

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


используйте ниже bean для HibernateTemplate на контекст приложения.

<bean id="template" class="org.springframework.orm.hibernate4.HibernateTemplate">  
        <property name="sessionFactory" ref="mysessionFactory"></property>
        <property name="checkWriteOperations" value="false"></property>
        </bean>

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

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

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


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


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

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

1) добавьте @Transactional над вами методы работы базы данных и 2) Убедитесь, что у вас есть аннотации driven transation manager

добавить

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


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

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

Я убрал

mode="aspectj"

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