Когда Hibernate сбрасывает сеанс, как он определяет, какие объекты в сеансе загрязнены?
Вопрос
Мое понимание гибернации заключается в том, что по мере загрузки объектов из базы данных они добавляются в сеанс.В различные моменты, в зависимости от вашей конфигурации, сеанс сбрасывается.На этом этапе измененные объекты записываются в базу данных.
Как Hibernate определяет, какие объекты являются "грязными" и должны быть записаны?
Перехватывают ли прокси, сгенерированные Hibernate, назначения полям и добавляют ли объект в грязный список в сеансе?
Или Hibernate просматривает каждый объект в Сеансе и сравнивает его с исходным состоянием объектов?
Или что-то совершенно другое?
Решение
Hibernate использует / может использовать генерацию байт-кода (CGLIB), чтобы он знал, что поле загрязнено, как только вы вызываете установщик (или даже присваиваете полю afaict).
Это немедленно помечает это поле / объект как загрязненное, но не уменьшает количество объектов, которые необходимо проверить на загрязнение во время очистки.Все, что это делает, - это влияет на реализацию org.hibernate.engine.EntityEntry.requiresDirtyCheck()
.IT все еще выполняет сравнение по полю, чтобы проверить наличие загрязнений.
Я говорю вышесказанное, основываясь на недавнем просмотре исходного кода (3.2.6GA), со всем доверием, которое это добавляет.Представляющими интерес являются:
SessionImpl.flush()
запускаетonFlush()
событие.SessionImpl.list()
звонкиautoFlushIfRequired()
который запускаетonAutoFlush()
событие.(в таблицах, представляющих интерес).То есть запросы могут вызывать сброс.Интересно, что сброс не происходит, если нет транзакции.- Оба эти события в конечном итоге заканчиваются в
AbstractFlushingEventListener.flushEverythingToExecutions()
, который заканчивается (среди других интересных локаций) вflushEntities()
. - Это перебирает все объекты в сеансе (
source.getPersistenceContext().getEntityEntries()
) зовущийDefaultFlushEntityEventListener.onFlushEntity()
. - В конце концов вы оказываетесь в
dirtyCheck()
.Этот метод действительно вносит некоторые оптимизации в отношении грязных флагов CGLIB, но в итоге мы все равно перебираем каждую сущность.
Другие советы
Hibernate создает моментальный снимок состояния каждого объекта, который загружается в Сеанс.При сбросе каждый объект в сеансе сравнивается с соответствующим моментальным снимком, чтобы определить, какие из них являются загрязненными.Инструкции SQL выдаются по мере необходимости, и моментальные снимки обновляются, чтобы отразить состояние (теперь чистых) объектов сеанса.
Взгляните на org.hibernate.event.def.DefaultFlushEntityEventListener.dirtyCheck Каждый элемент сеанса обращается к этому методу, чтобы определить, является ли он загрязненным или нет, путем сравнения с нетронутой версией (одной из кэша или одной из базы данных).
Механизм проверки "грязного" режима гибернации по умолчанию будет проходить через текущие подключенные объекты и сопоставлять все свойства с их начальными значениями времени загрузки.
Вы можете лучше представить себе этот процесс на следующей диаграмме:
Эти ответы являются неполными (в лучшем случае - я здесь не эксперт).Если у вас есть объект hib man в вашем сеансе, вы НИЧЕГО с ним не ДЕЛАЕТЕ, вы все равно можете получить обновление при вызове функции save() для него.когда?когда другой сеанс обновляет этот объект между вашими load() и save().вот мой пример этого: режим гибернации устанавливает грязный флаг (и выдает обновление), даже если клиент не изменил значение