Интегратор Hibernate вызывает сброс при использовании транзакций JPA вокруг запросов
Я работаю над Integrator
для Hibernate (справочная информация об интеграторах: https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch14.html), что при использовании слушателей должен Данные о том, как он хранится в БД и преобразовать его в другую форму для обработки во время выполнения. Это прекрасно работает при сохранении данных с помощью .persist()
однако есть странное поведение, связанное с транзакциями. Следующий код взят из собственного краткого учебного кода Hibernate:
// now lets pull events from the database and list them
entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
List<Event> result = entityManager.createQuery( "from Event", Event.class ).getResultList();
for ( Event event : result ) {
System.out.println( "Event (" + event.getDate() + ") : " + event.getTitle() );
}
entityManager.getTransaction().commit();
entityManager.close();
Обратите внимание на необычную транзакцию начала / фиксации, заключающую в себе запрос для выбора данных. Выполнение этого дает следующий вывод после завершения запроса:
01:01:59.111 [main] DEBUG org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(175) - committing
01:01:59.112 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(149) - Processing flush-time cascades
01:01:59.112 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.prepareCollectionFlushes(189) - Dirty checking collections
01:01:59.114 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.logFlushResults(123) - Flushed: 0 insertions, 2 updates, 0 deletions to 2 objects
01:01:59.114 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.logFlushResults(130) - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
01:01:59.114 [main] DEBUG org.hibernate.internal.util.EntityPrinter.toString(114) - Listing entities:
01:01:59.114 [main] DEBUG org.hibernate.internal.util.EntityPrinter.toString(121) - org.hibernate.tutorial.em.Event{date=2015-07-28 01:01:57.776, id=1, title=Our very first event!}
01:01:59.114 [main] DEBUG org.hibernate.internal.util.EntityPrinter.toString(121) - org.hibernate.tutorial.em.Event{date=2015-07-28 01:01:58.746, id=2, title=A follow up event}
01:01:59.115 [main] DEBUG org.hibernate.SQL.logStatement(109) - update EVENTS set EVENT_DATE=?, title=? where id=?
Hibernate: update EVENTS set EVENT_DATE=?, title=? where id=?
01:01:59.119 [main] DEBUG org.hibernate.SQL.logStatement(109) - update EVENTS set EVENT_DATE=?, title=? where id=?
Hibernate: update EVENTS set EVENT_DATE=?, title=? where id=?
01:01:59.120 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(113) - committed JDBC Connection
01:01:59.120 [main] DEBUG org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(201) - HHH000420: Closing un-released batch
01:01:59.121 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.releaseConnection(246) - Releasing JDBC connection
01:01:59.121 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.releaseConnection(264) - Released JDBC connection
01:01:59.121 [main] DEBUG org.hibernate.internal.SessionFactoryImpl.close(1339) - HHH000031: Closing
Похоже, что с Integrator
делает модификацию в рассматриваемом объекте, он помечается как "грязный", и после фиксации этой нечетной транзакции он обходит мои прослушиватели событий и записывает значение обратно в неправильном формате! Я немного покопался в коде и оказалось, что org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(FlushEvent, PersistenceContext)
вызывается выше и пытается получить слушателей для EventType.FLUSH_ENTITY
, К сожалению, слушатель добавил для этого EventType
никогда не называется в моем Integrator
, Как я могу написать свой Integrator
вести себя правильно в этом случае, чтобы я мог "отменить" преобразование, которое произошло с моими сущностями во время выполнения, и не сбросить неверное значение?
1 ответ
В конечном итоге проблема была связана с EventType
Слушатели событий добавлены с EventListenerRegistry
, То, что работало, использовало EventType.POST_LOAD
для всех операций чтения в сочетании с EventType.PRE_UPDATE
а также EventType.PRE_INSERT
for пишет, что вызывает вспомогательный метод для обработки обоих одинаково.
Чтобы предотвратить ненужные записи после обновления вашей сущности, рекомендуется сбросить данные, используемые для отслеживания, если сущность загрязнена в EntityEntry
называется loadedState
, Это частное поле в Hibernate 4, поэтому вам нужно использовать Reflection, однако в Hibernate 5 оно доступно через getLoadedState()
метод. Еще один недостаток - вам необходимо обновить значения "состояния", используемого при фактической очистке значений в базу данных PreInsertEvent
а также PreUpdateEvent
которые могут быть получены из getState()
метод, определенный в каждом.