#spring #hibernate #exception #jpa #orm
#spring #спящий режим #исключение #jpa #орм
Вопрос:
Рассмотрим следующий сценарий —
Существуют две таблицы (идентичные по схеме), называемые ActiveIssue
и ResolvedIssue
. Когда проблема активна, она находится в таблице ActiveIssue, а когда проблема решена, она перемещается в таблицу ResolvedIssue . Проблемы могут быть связаны друг с другом.
У меня есть метод, который выполняет следующее —
- Получить связанные проблемы для проблемы из ActiveIssue
- Получение связанных проблем для проблемы из ResolvedIssue
Перед вызовом этого метода я установил session.setFlushMode(FlushMode.MANUAL)
, чтобы избежать следующего сценария —
- Получить связанные проблемы из ActiveIssue
- В фоновом режиме проблема X решается и переходит из ActiveIssue в ResolvedIssue
- Получить связанные проблемы из ResolvedIssue (приводит к конфликту из-за проблемы X)
Однако я замечаю, что я сталкиваюсь с исключением WrongClassException даже при наличии этой логики. Например, я получаю
org.hibernate.WrongClassException: Object with id: 123456 was not of the
specified subclass ... ActiveIssue
(loaded object was of wrong class ... ResolvedIssue)
Я использую org.springframework.orm.hibernate3.support.HibernateDaoSupport
и вызываю Session session = getSession()
этот объект. ActiveIssue и ResolvedIssue оба являются производными от вызываемого базового класса Issue
. Я использую InheritanceType.TABLE_PER_CLASS
стратегию наследования для базового класса, поэтому ActiveIssue сопоставляется с таблицей ActiveIssue, а ResolvedIssue сопоставляется с таблицей ResolvedIssue.
Я не понимаю, почему возникает исключение WrongClassException, когда я явно установил для режима FlushMode значение MANUAL. Разве объекты в сеансе не должны быть согласованными?
Комментарии:
1. Пожалуйста, выполните трассировку стека!!
Ответ №1:
setFlushMode(...)
: Очистка — это процесс синхронизации базового постоянного хранилища с постоянным состоянием, хранящимся в памяти.
Проще говоря, он сообщит, когда обновлять / удалять (синхронизировать.) данные из памяти, которые берутся из базы данных.
Если пройти через FlushMode
это, вы придете к knwo, что установка FlushMode в РУЧНОЕ положение означает, что память будет синхронизирована. когда ты скажешь session.flush()
.
Рассмотрим сценарий, в котором один поток выполняет работу, переводя проблему X из ActiveIssue в ResolvedIssue, и в то же время другой поток вызывает 1. Get related issues for an issue from ActiveIssue
Итак, по вашему мнению, перед вызовом этого вы устанавливаете FlushMode на MANUAL, чтобы он не синхронизировался. перед выполнением запроса. СОГЛАСНО автору
FlushMode.АВТО : сеанс иногда сбрасывается перед выполнением запроса, чтобы гарантировать, что запросы никогда не возвращают устаревшее состояние.
Таким образом, когда вы запрашиваете в таблице Get related issues for an issue from ActiveIssue
конкретную проблему, X (123456) может быть перемещен в ResolvedIssue другим потоком. таким образом, идентификатор 123456 не имеет типа ActiveIssue
, так что вы получаете это исключение
Комментарии:
1. Почему вы используете FlushMode. РУКОВОДСТВО для транснациональных данных ?
2. Я согласен с этим ответом. Согласно Hibernate
FlushMode.MANUAL
, он полезен в данных только для чтения для повышения производительности. Этот режим очень эффективен для транзакций только для чтения.
Ответ №2:
Режим ручной очистки влияет только на ваш текущий сеанс, а не на любой другой конкурирующий поток. Каждый поток выполняется изолированно благодаря транзакциям. Когда вы перемещаете объект из одного типа в другой, может случиться так, что текущий сеанс содержит ссылку на старый тип (например, ActiveIssue ) для заданного идентификатора, в то время как вы пытаетесь сохранить / объединить объект другого типа (например, ResolvedIssue) с тем же идентификатором.
убедитесь, что вы всегда удаляете старую запись, удаляете изменения (даже АВТОМАТИЧЕСКИ), а затем добавляете новый тип для того же идентификатора.
Комментарии:
1. Что вы подразумеваете под удалением старой записи? Другой поток уже удалил запись из базы данных и переместил ее в новую таблицу. Если сеанс содержит ссылку на старый объект, как я могу удалить эти ссылки?
2. Если другой поток удалил его, вы получите оптимистичное исключение блокировки.