Строка StaleObjectstateException была обновлена ​​или удалена

Я получаю это исключение в контроллере веб-приложения на основе Spring Framework с использованием Hibernate. Я пробовал много способов противостоять этому, но не смог решить.

В методе контроллера, handleRequestInternalв базу данных поступают вызовы, в основном для "чтения", если только это не действие "отправить". Я использовал Spring Session, но перешел на getHibernateTemplate() и проблема все еще остается.

в основном, этот второй вызов базы данных вызывает это исключение. То есть:

1) getEquipmentsByNumber(number) {сначала оборудование выбирается из БД на основе "числа", которое имеет список свойств, а каждое свойство имеет список значений. Я перебираю эти значения (примитивные объекты Strings) для чтения переменных)

2) getMaterialById(id) {выбирает материалы на основе идентификатора}

Я понимаю, что второй вызов, скорее всего, вызывает "сброс" сеанса, но я только "читаю" объекты, тогда почему второй вызов вызывает исключение состояния устаревшего объекта в свойстве Equipment, если ничего не изменилось?

Я не могу очистить кеш после вызова, так как это вызывает исключения LazyException для объектов, которые я передаю представлению.

Я прочитал это: https://forums.hibernate.org/viewtopic.php?f=1&t=996355&start=0 но не смог решить проблему на основе предоставленных предложений.

Как я могу решить эту проблему? Любые идеи и мысли приветствуются.

ОБНОВЛЕНИЕ: что я только что проверил, что в функции getEquipmentsByNumber() после прочтения переменных из списка свойств, я делаю это: getHibernateTemplate().flush(); и теперь исключение находится в этой строке, а не вызове выборки материала (то есть getMaterialById(id)).

ОБНОВЛЕНИЕ: Прежде чем явно вызвать flush, я удаляю объект из кэша сеанса, чтобы в кэше не осталось устаревших объектов.

getHibernateTemplate().evict(equipment);
getHibernateTemplate().flush();

Хорошо, теперь проблема перешла к следующему извлечению из БД после того, как я это сделал. Я полагаю, что мне нужно пометить методы как синхронизированные и удалить объекты, как только я закончу читать их содержимое! это звучит не очень хорошо.

ОБНОВЛЕНИЕ: Сделано handleRequestInternal метод "синхронизирован". Ошибка исчезла. Конечно, не лучшее решение, но что делать! Пробовал в handleRequestInternal закрыть текущий сеанс и открыть новый. Но это приведет к тому, что другие части приложения не будут работать должным образом. Пытался использовать ThreadLocal это тоже не сработало.

4 ответа

Вы неправильно используете Hibernate, что заставляет его думать, что вы обновляете или удаляете объекты из базы данных.

Вот почему звоню flush() бросает исключение.

Одна из возможностей: вы неправильно "делитесь" сессией или сущностями через поля (ы) вашего сервлета или контроллера. Это основная причина, по которой "синхронизированный" изменит ваши симптомы ошибки. Краткое решение: никогда не делайте этого. Сессии и сущности не должны и не должны работать таким образом - каждый запрос должен обрабатываться независимо.

Другая возможность: unsaved-valueпо умолчанию 0 для полей типа "int". Вместо этого вы можете ввести их как "Integer", если вы действительно хотите использовать 0 в качестве действительного значения PK.

Третье предложение: используйте Hibernate Session явно, научитесь писать простой правильный код, который работает, а затем загрузите исходный код Java для библиотек Hibernate/ Spring, чтобы вы могли прочитать и понять, что эти библиотеки на самом деле делают для вас.

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

org.hibernate.StaleObjectStateException: строка была обновлена ​​или удалена другой транзакцией (или отображение несохраненного значения было неправильным): [com.rc.model.mexp.MerchantAccount#59132]

В нашем случае оказалось, что отображение было неправильным; мы имеем type="text" в отображении для одного поля, которое было средним типом в базе данных, и кажется, что Hibernate действительно ненавидит это, по крайней мере, при определенных обстоятельствах. Мы полностью удалили спецификацию типа из сопоставления для этого поля, и проблема была решена.

Теперь странно то, что в нашей производственной среде с предположительно проблемным отображением мы НЕ получаем это исключение. Кто-нибудь знает, почему это может быть? Мы используем одну и ту же версию MySQL - "5.0.22-log" (я не знаю, что означает "-log") - в средах разработки и разработки.

Вот 3 варианта (поскольку я точно не знаю, какой вид обработки Hibernate-сессии вы используете). Добавить один за другим и проверить:

Используйте двунаправленное отображение с inverse=true между родительским объектом и дочерним объектом, поэтому изменение в родительском или дочернем объекте будет правильно распространяться на другой конец отношения.

Добавить поддержку для Оптимистичной блокировки, используя TimeStamp или же Version колонка

Используйте запрос соединения, чтобы получить весь граф объектов [parent + children] вместе, чтобы вообще избежать второго вызова.

Наконец, если и только если ничего не работает: снова загрузите родительский Id (у вас это уже есть) и заполните измененные данные, затем обновите.

Жизнь будет хорошей!:)

Эта проблема была чем-то, что я испытал, и меня это очень расстраивало, хотя должно быть что-то странное в ваших вызовах DAO/Hibernate, потому что если вы выполняете поиск по идентификатору, нет причин получать устаревшее состояние, так как это просто поиск объекта.

Во-первых, убедитесь, что все ваши методы помечены @Transaction(required=true) // you'll have to look up the exact syntax

Однако это исключение обычно выдается при попытке внести изменения в объект, который был отсоединен от сеанса, из которого он был получен. Решение этой проблемы часто не простое и требует большего количества размещенного кода, чтобы мы могли точно видеть, что происходит; мое общее предложение было бы создать @Service который выполняет такие вещи в одной транзакции

Другие вопросы по тегам