Когда Hibernate сбрасывает сеанс, как он определяет, какие объекты в сеансе загрязнены?

Насколько я понимаю, Hibernate заключается в том, что по мере загрузки объектов из БД они добавляются в сеанс. В различные моменты, в зависимости от вашей конфигурации, сеанс сбрасывается. На этом этапе измененные объекты записываются в базу данных.

Как Hibernate определяет, какие объекты «грязные» и должны быть написаны?

Перехватывают ли прокси, созданные Hibernate, назначения полей и добавляют ли объект в грязный список в сеансе?

Или Hibernate смотрит на каждый объект в сеансе и сравнивает его с исходным состоянием объектов?

Или что-то совсем другое?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
17
0
14 124
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

В Hibernate ситуация такова, как вы описываете: атрибут путем сравнения атрибутов объектов моментальных снимков с объектами сеанса. Это контрастирует с Datanucleus (в режиме JDO или JPA), где его расширение байтового кода позволяет ему делать очень интеллектуальные, высокопроизводительные вещи, такие как добавление грязного флага к каждому постоянному классу. Это означает, что во время сброса в Datanucleus загрязнение любого объекта - это простая проверка флага грязности. Вам не нужно быть Эйнштейном, чтобы понять, почему с любой нетривиальной объектно-ориентированной моделью предметной области, почему сброс Hibernate занимает намного больше времени.

Volksman 15.03.2014 03:24

Взгляните на org.hibernate.event.def.DefaultFlushEntityEventListener.dirtyCheck Каждый элемент в сеансе обращается к этому методу, чтобы определить, загрязнен он или нет, сравнивая его с нетронутой версией (один из кеша или один из базы данных).

Ответ принят как подходящий

Hibernate использует / может использовать генерацию байт-кода (CGLIB), чтобы он знал, что поле загрязнено, как только вы вызываете установщик (или даже назначаете поле afaict).

Это немедленно помечает это поле / объект как грязное, но не уменьшает количество объектов, которые необходимо проверить на грязные данные во время сброса. Все это влияет на реализацию org.hibernate.engine.EntityEntry.requiresDirtyCheck(). Все еще выполняет сравнение поля за полем для проверки загрязнения.

Я говорю вышеизложенное на основе недавнего просмотра исходного кода (3.2.6GA) с любой добавленной достоверностью. Достопримечательности:

  • SessionImpl.flush() запускает событие onFlush().
  • SessionImpl.list() вызывает autoFlushIfRequired(), который запускает событие onAutoFlush(). (на интересующих вас столах). То есть запросы могут вызывать сброс. Интересно, что сброса не происходит, если нет транзакции.
  • Оба эти события в конечном итоге заканчиваются на AbstractFlushingEventListener.flushEverythingToExecutions(), который заканчивается (среди других интересных мест) на flushEntities().
  • Это перебирает каждый объект в сеансе (source.getPersistenceContext().getEntityEntries()), вызывающий DefaultFlushEntityEventListener.onFlushEntity().
  • В конце концов вы окажетесь на dirtyCheck(). Этот метод делает некоторые оптимизации по отношению к грязным флагам CGLIB, но мы все равно перебираем каждую сущность в цикле.

Пожалуйста, объясните лучше: если грязный флаг не уменьшает количество объектов, которые нужно грязно-проверять, в чем его полезность? Более того, в источнике я вижу два разных грязных флага: один находится в AbstractFieldInterceptor и проверяется EntityEntry.requiresDirtyCheck (), другой находится в AbstractPersistentCollection и комментируется: «коллекции обнаруживают изменения, внесенные через их открытый интерфейс, и помечают себя как грязные, как производительность. оптимизация »(не знаю, где это проверено в коде).

Pino 14.09.2012 18:38

@Matt Quail, я не смог найти грязные флаги, о которых вы говорите, есть только тот, который можно использовать, только если используется инструментарий байт-кода времени сборки.

Stanislav Bashkyrtsev 28.09.2014 09:57

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

Вы можете лучше представить себе этот процесс на следующей диаграмме:

Default automatic dirty checking

Эти ответы неполные (в лучшем случае - я здесь не эксперт). Если у вас есть сущность hib man в вашем сеансе, вы НИЧЕГО не делаете с ней, вы все равно можете получить обновление, когда вы вызываете для нее save (). когда? когда другой сеанс обновляет этот объект между вашими load () и save (). вот мой пример: hibernate устанавливает грязный флаг (и выдает обновление), даже если клиент не изменил значение

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