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$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);
он будет работать, но иногда с тем же объектом и вызовом того же метода он не работает, но, похоже, он зависит от того, как Я получаю объект в первую очередь.
Пример: скажем, у меня есть таблица с тремя полями: id, type, length. Что может случиться, так это то, что если я получу объект по id и обновляю длину, тогда он будет работать. Если я получаю его по типу и обновляю длину, то это не сработает. Итак, что я делал до сих пор, чтобы избежать проблемы, - это получить объект методом, который не вызывает проблемы позже, но это становится все более и более раздражающим, чтобы попытаться найти способ, который работает.
Кроме того, теперь у меня есть это исключение при попытке создать объект (но не все из них, только на одной конкретной таблице), и не может найти способ обходного пути. И я попытался добавить @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);
}
Ответы
Ответ 1
Я изменил один сеанс из фильтра просмотра. Решение проблемы:
<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>
Ответ 2
Это сообщение об ошибке обычно отображается при использовании Spring OpenSessionInViewFilter и пытается выполнять операции сохранения за пределами Spring - управляемая транзакция. Фильтр устанавливает сеанс в FlushMode.NEVER/MANUAL (в зависимости от версий Spring и Hibernate, которые вы используете - они примерно эквивалентны). Когда механизм транзакции Spring начинает транзакцию, он меняет режим очистки на "COMMIT". По завершении транзакции он устанавливает его обратно в NEVER/MANUAL, если это необходимо. Если вы абсолютно уверены, что этого не происходит, то следующим наиболее вероятным виновником является небезопасное использование сеанса. Сессия Hibernate должна использоваться только в одном потоке. Если он пересекает потоки, могут возникнуть всевозможные хаосы. Обратите внимание, что объект, загруженный из Hibernate, может содержать ссылку на сеанс, в который он был загружен, и передача сущности через потоки может, таким образом, также вызвать доступ к сеансу из другого потока.
Ответ 3
Я просто наткнулся на это тоже. Мне нужно было изменить режим флеша в Spring OpenSessionInViewFilter на ручной, и вдруг я начал получать это исключение. Я выяснил, что проблемы возникали в методах, которые не были аннотированы как @Transactional, поэтому я предполагаю, что Spring неявно рассматривает весь код доступа к данным вне таких методов, как только чтение. Аннотирование метода решает проблему.
Другим способом является вызов метода setCheckWriteOperations объекта HibernateTemplate.
Ответ 4
добавить
@Transactional
над вашей функцией
Ответ 5
Попробуйте использовать этот
hibernateTemplate = new HibernateTemplate(sessionFactory);
hibernateTemplate.setCheckWriteOperations(false);
Ошибка должна исчезнуть, поскольку шаблон не проверяет, используете ли вы транзакцию.
Ответ 6
Используйте bean для HibernateTemplate в контексте приложения.
<bean id="template" class="org.springframework.orm.hibernate4.HibernateTemplate">
<property name="sessionFactory" ref="mysessionFactory"></property>
<property name="checkWriteOperations" value="false"></property>
</bean>
Ответ 7
Ниже для меня работает часть кода.
hibernateTemplate = new HibernateTemplate(sessionFactory);
hibernateTemplate.setCheckWriteOperations(false);
Ответ 8
Вы должны забыть добавить аннотацию @Transactional к вашему классу/методу службы DAO, это укажет, что ваша операция с базой данных будет обрабатываться с помощью транзакции spring.
Ответ 9
У меня была та же проблема, и после одного дня расследования я заметил следующее выражение
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
Я удалил
mode="aspectj"
и проблема исчезла